home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Unix / maclayersunixend1.30.shar / 1.30 / layers.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  77KB  |  3,196 lines

  1. /********                    Layers.c
  2. *********
  3. *********    Layers - MacLayers Multiwindow BSD Socket Driver
  4. *********
  5. *********            David W. Trissel and Eric C. Rosen
  6. *********
  7. ********* The sockets handling portion of this control module is based 
  8. ********* upon 'screen' by Oliver Laumann whose copyright remains below. 
  9. ********* The rest is
  10.  *
  11.  *             Copyright (C) 1993 by Eric C. Rosen
  12.  *             Copyright (C) 1989-1992 by David W. Trissel
  13.  *
  14.  *              Not derived from licensed software.
  15.  *
  16.  * Permission is granted to freely use, copy, modify, and redistribute
  17.  * this software, provided that no attempt is made to gain profit from it,
  18.  * the authors are not construed to be liable for any results of using the
  19.  * software, alterations are clearly marked as such, and this notice is
  20.  * not modified.
  21.  *
  22.  */
  23.  
  24. static char LayersVersion[] = "layers 1.30 17-May-1993";
  25.  
  26. /* Layers Changes:
  27.  
  28.  
  29.     Version 1.00  17-Mar-1990
  30.  
  31.         First public release.
  32.  
  33.     Version 1.01  10-May-1990
  34.  
  35.         * Fixed bug 001 which caused failure of protocol mode to establish
  36.           if USRLIMIT check is enabled and USRLIMIT or more login shells 
  37.           are already active. Could also keep new login layer windows from
  38.           responding until another layer is brought up front and then sent
  39.           back.
  40.  
  41.     Version 1.01  27-Jun-1991
  42.  
  43.         * Corrected bugs where utmp login record or initial tty settings
  44.           may not be restored if initial client connection fails
  45.  
  46.         * Added return code support so shell scripts can determine what
  47.           happened:
  48.                       0  - layers connected, ran and terminated sucessfully
  49.                       1  - not running under MacLayers client terminal
  50.                       2  - layers terminated due to some abnormal condition
  51.                       3  - SIGQUIT or SIGTERM signal received
  52.                       4  - SIGHUP signal received
  53.  
  54.         * Rewrote protocl.c to avoid using scanf which was prohibiting 7-bit 
  55.           communication lines from working under layers mode. (Scanf does
  56.           not work on 7-bit line in RAW mode since high bit invalidates
  57.           its character checking.)
  58.  
  59.         * Removed internal TERMCAP entries for "ic" and "dc" (insert character
  60.           and delete character) which are not ANSI standard. The "dc" collided
  61.           with a real vt-100 capability that the author did not know about!
  62.           (Note of 6/11/91: perhaps "dc" and "ic" will be reinstated with 
  63.           their true ANSI definitions. 6/11/91)
  64.  
  65.         * If socket directory not 0700 then try to change it to 0700.
  66.  
  67.     Version 1.10  26-Sep-1991
  68.  
  69.         * Host/client version ID sharing at startup. This is transparent on 
  70.           both sides with older versions.
  71.  
  72.             1) If client identifies itself as at least 1.10 MacLayers 
  73.                add vt102 TERMCAP entries for ic, dc, IC, DC with correct
  74.                capabilities. (V1.00 had incorrect ones-see above.)
  75.  
  76.  
  77.     Version 1.30 10-May-1993 
  78.  
  79.         * Added support for .layersrc file.
  80.         * Added support for A/UX, IRIX, AIX, ULTRIX, and NeXT systems; 
  81.             should work on most System V platforms now with a few flags set.
  82.         * Cleaned up source (a little); removed some unused variables.
  83. */
  84.  
  85.  
  86. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  87.  * Not derived from licensed software.
  88.  *
  89.  * Permission is granted to freely use, copy, modify, and redistribute
  90.  * this software, provided that no attempt is made to gain profit from it,
  91.  * the author is not construed to be liable for any results of using the
  92.  * software, alterations are clearly marked as such, and this notice is
  93.  * not modified.
  94.  *
  95.  *    Modified by Patrick Wolfe (pat@kai.com, kailand!pat)
  96.  *    Do whatever you want with (my modifications of) this program, but
  97.  *    don't claim you wrote them, don't try to make money from them, and
  98.  *    don't remove this notice.
  99.  */
  100.  
  101. /*
  102.  *    Beginning of User Configuration Section
  103.  *
  104.  *    You can set these variables from the command-line via the
  105.  *    provided makefile. Type 'make' for details.
  106.  */
  107.  
  108.  
  109. /*
  110.  * GETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD)
  111.  *              and the getttyent(3) library functions.
  112.  *
  113.  */
  114.  
  115. /*
  116.  *    These options are best set within the code. Don't change these unless
  117.  *    you know what you are doing.
  118.  */
  119.  
  120. /*
  121.  * LOGINDEFAULT -- if set to 1 (one), windows will login (add entries to
  122.  *                 /etc/utmp) by default.  Set to 0 if you don't want this.
  123.  *                 (Also see USRLIMIT below). [NOTE: current code always
  124.  *                 logs layer #1 only unless -l option used on 'layers'
  125.  *                 command.]
  126.  */
  127. #define LOGINDEFAULT 0
  128.  
  129. /*
  130.  * USRLIMIT  --   count all non-null entries in /etc/utmp before adding a 
  131.  *                   new entry. Some machine manufacturers (incorrectly) count 
  132.  *                   logins by counting non-null entries in /etc/utmp (instead 
  133.  *                   of counting non-null entries with no hostname and not on 
  134.  *                   a pseudo tty). Sequent does this, so you might reach your 
  135.  *                   limited user license early.
  136.  */
  137. #define USRLIMIT 64
  138.  
  139. /*
  140.  * SOCKDIR      -- If defined, this directory is where layers sockets will be 
  141.  *                   placed, (actually in a subdirectory by the user's loginid).
  142.  *                   This is neccessary because NFS doesn't support socket 
  143.  *                   operations, and many people's homes are on NFS mounted 
  144.  *                   partitions.  Layers will create this directory if it needs 
  145.  *                   to.
  146.  */
  147. #define SOCKDIR "/tmp/layers"    /* NFS doesn't support named sockets */
  148.  
  149. /*
  150.  *    End of User Configuration Section
  151.  */
  152.  
  153. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  154.  
  155. /*
  156.  *    Begin pre-defined environment definition section:
  157.  */
  158.  
  159. /* Apple A/UX: */
  160. #ifdef AUX
  161. #define SYSVUTMP
  162. #define USE_TERMIO
  163. #undef USRLIMIT
  164. #endif
  165.  
  166. /* Silicon Graphics IRIX: */
  167. #ifdef IRIX
  168. #define POSIXTTY
  169. #define SYSVUTMP
  170. #define    IGNORE_SIGHUP
  171. #undef GETTTYENT
  172. #undef USRLIMIT
  173. #endif
  174.  
  175. /* NeXT: */
  176. #ifdef NeXT
  177. #define GETTTYENT
  178. #endif
  179.  
  180. /* IBM AIX: */
  181. #ifdef AIX
  182. #define    USE_TERMIO
  183. #define    IGNORE_SIGHUP
  184. #endif
  185.  
  186. /* DEC ULTRIX: */
  187. #ifdef ULTRIX
  188. #define GETTTYENT
  189. #endif
  190.  
  191.  
  192. /* Data General Aviion: */
  193. #ifdef DG_AVIION
  194. #define _BSD_WAIT_FLAVOR 1   /* to avoid wait3 WIFSTOPPED macro error */
  195. #define USE_TERMIO
  196. #define    IGNORE_SIGHUP
  197. #endif
  198.  
  199. /* System V machines use sigset instead of signal to auto-reactivate handlers */
  200. #ifdef DG_AVIION
  201. #define SIGNAL(a,b) sigset(a,b)
  202. #endif
  203.  
  204. #ifdef SVR4
  205. #define POSIXTTY
  206. #undef USRLIMIT
  207. #define       index   strchr
  208. #endif
  209.  
  210. #ifndef SIGNAL
  211. #define SIGNAL(a,b) signal(a,b)
  212. #endif
  213.  
  214. /*
  215.  *    End of predefined envirnment configuration section.
  216.  */
  217.  
  218. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  219.  
  220. /*
  221.  * Begin include-files:
  222.  */
  223.  
  224. #if defined(IRIX) || defined(SVR4)
  225. #include <unistd.h>
  226. #endif
  227.  
  228. #include <stdio.h>
  229.  
  230. #ifdef NeXT
  231. #include <libc.h>
  232. #endif
  233.  
  234. #include <signal.h>
  235.  
  236. #ifdef __STRICT_BSD__
  237. #define    SIGTYPE int
  238. #else
  239. #define    SIGTYPE void
  240. #endif 
  241.  
  242. /*
  243.  * Some systems do not have <string.h>; others don't have <strings.h>:
  244.  */
  245. #if !defined(SEQUENT)
  246. #include <string.h>
  247. #endif
  248. #if !defined(SVR4)
  249. #include <strings.h>
  250. #endif
  251.  
  252. #include <errno.h>
  253. #include <ctype.h>
  254. #include <utmp.h>
  255. #include <pwd.h>
  256. #include <nlist.h>
  257. #include <fcntl.h>
  258. #include <sys/types.h>
  259. #ifndef FD_SETSIZE
  260. typedef int fd_set;
  261. #endif
  262. #include <sys/time.h>
  263. #include <sys/file.h>
  264. #include <sys/wait.h>
  265. #include <sys/socket.h>
  266. #include <sys/un.h>
  267. #include <sys/stat.h>
  268. #include <sys/dir.h>
  269. #ifndef POSIXTTY
  270. #include <sys/ioctl.h>
  271. #endif
  272.  
  273. #ifdef SVR4
  274. #include <utmpx.h>
  275. #include <sys/stropts.h>
  276. #endif
  277.  
  278.  
  279. #include "layers.h"
  280.  
  281. #ifdef GETTTYENT
  282. #include <ttyent.h>
  283. #else
  284. static struct ttyent
  285.   { char *ty_name;
  286.   } *getttyent();
  287. static char *tt, *ttnext;
  288. static char ttys[] = "/etc/ttys";
  289. #endif
  290.  
  291. #ifndef FSCALE
  292. #define FSCALE 1000.0        /* Sequent doesn't define FSCALE...grrrr */
  293. #endif
  294.  
  295. #ifdef  USRLIMIT
  296. struct utmp utmpbuf;
  297. int UserCount;
  298. #endif
  299.  
  300. #define Ctrl(c) ((c)&037)
  301.  
  302. /* C library items */
  303. extern char **environ;
  304. extern errno;
  305. extern sys_nerr;
  306. extern char *sys_errlist[];
  307. #ifndef NeXT
  308. extern char *malloc(), *getenv();
  309. extern char *getlogin(), *ttyname();
  310. #endif
  311.  
  312. /* Local items */
  313. static SIGTYPE FAbort(), SigHup(), SigChld(); 
  314. static void AddCap(), FinitTerm();
  315. static char *MakeTermcap(), *Filename(), **SaveArgs(), *GetTtyName(); /* [SaveArgs UNUSED] */
  316. static void    InitWorld(), ClearShape(), BuildTitle(), KillPG();
  317. static void SetWindowSize(), RemoveTtyFromUtmp(), RestoreRealUtmp(), InitUtmp();
  318. static int SetUtmp();
  319. static int    ProcessGeo();
  320.  
  321. static int    loginflag = -1;
  322. static char PtyName[32], TtyName[32];
  323. static char *ShellProg;
  324. static char *ShellArgs[2];
  325. static inlen;    /* [UNUSED] */
  326. static ESCseen;    /* [UNUSED] */
  327. static GotSignal;
  328. static char DefaultShell[] = "/bin/sh";
  329. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  330. static char PtyProto[] = "/dev/ptyXY";
  331. static char TtyProto[] = "/dev/ttyXY";
  332. static int TtyMode = 0622;
  333. static struct stat RealTtyStat;                    /* Real tty stat */
  334. static char RealTtyName[32] = "";                /* Real tty name */
  335. static int    RealTtyMode = 0;                    /* Real tty mode */
  336. static int    Oumask;                                /* Original user's umask */
  337. static char SockPath[512];
  338. #ifdef SOCKDIR
  339. static char SockDir[] = SOCKDIR;
  340. #else
  341. static char SockDir[] = ".layers";
  342. #endif
  343. static char *SockNamePtr, *SockName;
  344. static ServerSocket;
  345. static char *NewEnv[MAXARGS];
  346. static char Esc = Ctrl('a');    /* [UNUSED] */
  347. static char MetaEsc = 'a';        /* [UNUSED] */
  348. static char *home;
  349. static Abortonmsg = 0;
  350. static Resetenvonmsg = 0;
  351. static utmp, utmpf;
  352. static char *LoginName;
  353. static mflag, nflag, fflag;
  354. static rflag;                    /* [UNUSED] */
  355. static char HostName[MAXSTR];
  356. static char *myname;
  357. static DevTty;
  358.  
  359. #ifdef POSIXTTY
  360. #include <termios.h>
  361.  
  362. static struct termios OldMode, NewMode;
  363. #ifdef IRIX
  364. #define SetTTY(fd, mode) ioctl(fd, TCSETA, mode)
  365. #define GetTTY(fd, mode) ioctl(fd, TCGETA, mode)
  366. #else
  367. #define SetTTY(fd, mode) ioctl(fd, TCSETS, mode)
  368. #define GetTTY(fd, mode) ioctl(fd, TCGETS, mode)
  369. #endif /* IRIX */
  370.  
  371. #else
  372. #ifdef USE_TERMIO
  373. #include <termio.h>
  374. struct termio OldMode, NewMode;
  375.  
  376. #else
  377. #include <sgtty.h>
  378. static struct mode {
  379.     struct sgttyb m_ttyb;
  380.     struct tchars m_tchars;
  381.     struct ltchars m_ltchars;
  382.     int m_ldisc;
  383.     int m_lmode;
  384. } OldMode, NewMode;
  385.  
  386. #endif /* AIX */
  387. #endif /* POSIXTTY */
  388.  
  389. #define MSG_CREATE    0
  390. #define MSG_ERROR     1
  391.  
  392. struct msg
  393.   {
  394.     int type;
  395.     union
  396.       { struct
  397.           {    int    lflag;                /* login flag */
  398.             struct Shape shape;        /* window shape */
  399.             int nargs;
  400.             char line[MAXLINE];
  401.             char dir[1024];
  402.           } create;
  403.         char message[MAXLINE];
  404.       } m;
  405.   };
  406.  
  407.  
  408.             /* dynamic keyboard input buffer definition */
  409. struct Kbuff
  410.   {    struct Kbuff * next;            /* next buffer in chain (or NULL) */
  411.     int            size;                /* size of data in this buffer */
  412.     int            offset;                /* start of first data in buffer */
  413.     unsigned char text[IOSIZE];        /* text buffer itself */
  414.   };
  415.  
  416.             /* World layer definition */
  417. struct Layer {
  418.     int        chan;                    /* channel represented by this layer */
  419.     int        allocated;                /* layer allocated */
  420.     int        ptyfd;                    /* psuedo tty */
  421.     int        ptymask;                /* mask for pty descriptor */
  422.     int        lpid;                    /* layer head process ID */
  423.     int        slot;                    /* utmp slot number */
  424.     struct Kbuff *kbuff;            /* keyboard input buffers */
  425.     struct Shape shape;                /* Shape structure to/from MacLayers */
  426.     char    cmd[MAXSTR];            /* command to execute */
  427.     char    tty[MAXSTR];            /* psuedo tty ID */
  428.     };
  429.  
  430. static struct Layer World[MAXPCHAN]; /* all layer structures */
  431.  
  432. static int rows = 24;                /* default window height in lines */
  433. static int cols = 80;                /* default window width in chars */
  434. static char Termcap[1024];
  435. static char Term[MAXSTR] = "TERM=";    /* window's terminal type */
  436. static char    *UserTerm;                /* terminal ID we are mimmicing */
  437. static int flowctl;
  438. static tcLineLen = 100;
  439.  
  440. #define EXITNORMAL        0            /* normal exit - connection succeeded */
  441. #define EXITNOMACLAYERS    1            /* not running to MacLayers terminal */
  442. #define EXITABNORMAL    2            /* something wrong generic error */
  443. #define EXITSIGQUIT        3            /* TERM or QUIT signal got us */
  444. #define EXITSIGHUP        4            /* HUP signal got us */
  445.  
  446. static exitcode = EXITABNORMAL;        /* default to abnormal exit */
  447.  
  448. /* co#80 and li$24 added dynamically for proper window size */
  449. static char TermcapConst1[] = "TERMCAP=SC|";
  450.  
  451. #ifdef IRIX
  452. static char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\
  453.     :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\
  454.     :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\
  455.     :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\
  456.     :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\
  457.     :rf=/usr/lib/tabset/vt100:\\\n\
  458.     :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E>:\\\n\
  459.     :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\
  460.     :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\
  461.     :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\
  462.     :";
  463. #else
  464. static char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\
  465.     :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\
  466.     :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\
  467.     :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\
  468.     :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\
  469.     :rf=/usr/lib/tabset/vt100:\\\n\
  470.     :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E[?1l\\E>:\\\n\
  471.     :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\
  472.     :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\
  473.     :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\
  474.     :";
  475. #endif
  476.  
  477.  /* The following supported by MacLayers versions 1.1 and later */
  478.  /* ANSI insert characters and delete characters */
  479. static char TermcapConst101[] = "ic=\\E[@:dc=\\E[P:IC=\\E[%d@:DC=\\E[%dP:";
  480.  
  481. int        Dflag;                            /* debug dump flag */
  482. int        Clientlevel = 1;                /* client protocol (Default to V1.00) */
  483. int        Protocollevel = 1;                /* effective protocol (default 1) */
  484.  
  485. #ifdef IRIX
  486. static void ignore_alarm()
  487. {
  488.     signal(SIGALRM, ignore_alarm);
  489. }
  490. #endif
  491.  
  492. #ifdef SVR4
  493. #include <sys/resource.h>
  494.  
  495. static int getdtablesize()
  496. {
  497.     struct rlimit rl;
  498.  
  499.     (void) getrlimit(RLIMIT_NOFILE, &rl);
  500.     return rl.rlim_cur;
  501. }
  502. #endif
  503.  
  504.  
  505.                             /* main() */
  506. int
  507. main(ac, av)
  508. int    ac;
  509. char **av;
  510. {
  511.     extern int Initlink();
  512.     void Msg(), SigHandler();
  513.     static void SendCreateMsg(), MakeNewEnv();
  514.     static SetMode();
  515.  
  516. #ifndef POSIXTTY
  517.     static void GetTTY(), SetTTY();
  518. #endif
  519.  
  520.     static int GetSockName(), MakeClientSocket(), MakeServerSocket(),
  521.     MakeWindow(), ReadRc(); 
  522.     static void ReceiveMsg();
  523.  
  524.     register n;
  525.     register len;
  526.     register struct Layer *layer;
  527.     char    *ap;
  528.     char    *clienttitle = NULL;
  529.     struct passwd *ppp;
  530.     int        s;
  531.     int        r;                            /* read fd test bits */
  532.     int        w;                            /* write fd test bits */
  533.     int        stall;                        /* stall flag for priority channel */
  534.     int        fderr;                        /* error fd test bits */
  535.     struct timeval tv;
  536.     struct Shape shape;                    /* window shape */
  537.     char    buf[IOSIZE];
  538.     char    rc[256];
  539.     struct stat st;
  540.     struct Kbuff *kbptr;                /* input keyboard buffer pointer */
  541.  
  542.     time_t    now;                        /* [UNUSED] */
  543.  
  544.     Abortonmsg = 1;                        /* quit if message generated */
  545.     ClearShape(&shape);                    /* initialize shape structure */
  546.     myname = (ac == 0) ? "layers" : av[0];
  547.     InitWorld();                        /* clear World array structures */
  548.  
  549.     while (ac > 0)
  550.       {    ap = *++av;
  551.         if (--ac > 0 && *ap == '-')
  552.           {    switch (ap[1])
  553.             { case 'l':        /* login this command line */
  554.                 loginflag = 1;
  555.                 break;
  556.  
  557.               case 'd':        /* dump debugging flag */
  558.                 Dflag = 1;
  559.                 (void) freopen("layers.dump", "a", stderr); /* append mode */
  560. #ifdef SEQUENT
  561.                 setlinebuf(stderr);
  562. #else
  563.                 setvbuf(stderr, NULL, _IOLBF, 0);
  564. #endif
  565.                 break;
  566.  
  567.               case 'u':        /* do not login this command line */
  568.                 loginflag = 0;
  569.                 break;
  570.  
  571.               case 'm':        /* force this to be master and not a client */
  572.                 mflag = 1;
  573.                 break;
  574.  
  575.               case 'n':        /* no flow control */
  576.                 nflag = 1;
  577.                 break;
  578.  
  579.               case 'f':        /* flow control on */
  580.                 fflag = 1;
  581.                 break;
  582.  
  583.               case 'v':        /* do nothing but issue layers version */
  584.                 printf("%s\n", LayersVersion);
  585.                 exit(EXITNORMAL);
  586. /*
  587.               case 't':
  588.                 if (ac > 1) {
  589.                     clienttitle = *(++av);
  590.                     ac--;
  591.                 }
  592.                 break;
  593. */
  594.  
  595.               case 'g':
  596.                 if (ac > 1) {
  597.                     if (ProcessGeo(&shape, *(++av))) {
  598.                         printf("%s: invalid geometry argument \"%s\"\n", myname, *av);
  599.                         exit(EXITABNORMAL);
  600.                     }
  601.                     ac--;
  602.                 }
  603.                 break;
  604.  
  605.               default:
  606.             help:
  607.                 Msg (0,"Use: %s [-f] [-g geometry-str] [-l | -u] [-m] [-n] [cmd args]\n", myname);
  608.  
  609.             } /* end switch on '-' option */
  610.  
  611.         } /* end if '-' */
  612.  
  613.         else
  614.             break;
  615.  
  616.       } /* end while parameters */
  617.  
  618.     if (nflag && fflag)
  619.         Msg (0, "-f and -n are conflicting options.");
  620.  
  621.     if ((ShellProg = getenv ("SHELL")) == 0)
  622.         ShellProg = DefaultShell;
  623.     DO DEBUG("ShellProg %s\n", ShellProg);
  624.  
  625.     /* we mimmic the user's $TERM ID */
  626.     if ((UserTerm = getenv("TERM")) == 0)
  627.         UserTerm = "layers";                /* use "layers" if none */
  628.     (void) strcat(Term, UserTerm);
  629.     DO DEBUG("%s\n", Term);
  630.  
  631.     ShellArgs[0] = ShellProg;
  632.     if (ac == 0)
  633.       { ac = 1;
  634.         av = ShellArgs;
  635.         shape.wattr |= Wa_shell;            /* indicate a shell window */
  636.       }
  637.  
  638.     if ((home = getenv ("HOME")) == 0)
  639.         Msg (0, "$HOME is undefined.");
  640.     DO DEBUG("home %s\n", home);
  641.  
  642.     if ((LoginName = getlogin ()) == NULL || LoginName[0] == '\0')
  643.       {
  644.         if ((ppp = getpwuid(getuid())) == 0) {
  645.             Msg(0, "Can't get login-name from passwd file.");
  646.                exit(EXITABNORMAL);
  647.         }
  648.         LoginName = ppp->pw_name;
  649.       }
  650.     DO DEBUG("LoginName %s\n", LoginName);
  651.  
  652.     if ((Oumask=umask(0)) == -1)
  653.         Msg (errno, "Cannot change umask to zero");
  654.     DO DEBUG("Original umask o%o\n", Oumask);
  655.  
  656. #ifdef SOCKDIR
  657.     if (stat (SOCKDIR, &st) == -1)
  658.       {    if (errno == ENOENT)
  659.           { if (mkdir (SOCKDIR, 0777) == -1)
  660.                 Msg (errno, "Cannot make directory %s", SOCKDIR);
  661.             (void) chown (SOCKDIR, 0, 0);
  662.           }
  663.         else
  664.             Msg (errno, "Cannot get status of %s", SOCKDIR);
  665.       }
  666.     else
  667.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  668.             Msg (0, "%s is not a directory.", SOCKDIR);
  669.         if ((st.st_mode & 0777) != 0777)
  670.             Msg (0, "Directory %s must have mode 777.", SOCKDIR);
  671.       }
  672.     sprintf (SockPath, "%s/%s", SockDir, LoginName);
  673. #else
  674.     sprintf (SockPath, "%s/%s", home, SockDir);
  675. #endif
  676.     DO DEBUG("SockPath %s\n", SockPath);
  677.  
  678.     if (stat (SockPath, &st) == -1)
  679.       { if (errno == ENOENT)
  680.           { if (mkdir (SockPath, 0700) == -1)
  681.                 Msg (errno, "Cannot make directory %s", SockPath);
  682.             (void) chown (SockPath, getuid (), getgid ());
  683.             DO DEBUG("SockPath directory made\n");
  684.           }
  685.         else
  686.             Msg (errno, "Cannot get status of %s", SockPath);
  687.       }
  688.     else
  689.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  690.                Msg (0, "%s is not a directory.", SockPath);
  691.         if ((st.st_mode & 0777) != 0700)
  692.           { if (chmod(SockPath, 0700) == -1)
  693.                 Msg(0, "Cannot change directory %s to mode 700.", SockPath);
  694.           }
  695.         if (st.st_uid != getuid ())
  696.             Msg (0, "You are not the owner of %s.", SockPath);
  697.       }
  698.  
  699.     (void) strcpy(RealTtyName, GetTtyName());        /* real tty name */
  700.     if (stat(RealTtyName, &RealTtyStat) == -1)        /* get current mode */
  701.         Msg(errno, "Cannot get status of %s", RealTtyName);
  702.     DO DEBUG("Mode of %s is %#o\n", RealTtyName, RealTtyStat.st_mode);
  703.     RealTtyMode = RealTtyStat.st_mode;        /* save mode for later restore */
  704.  
  705.     (void) gethostname (HostName, MAXSTR);
  706.     HostName[MAXSTR-1] = '\0';
  707.     DO DEBUG("HostName %s\n", HostName);
  708.  
  709.     if (ap = index (HostName, '.'))
  710.         *ap = '\0';
  711.     if (ap)
  712.         DO DEBUG("*ap %s\n", *ap);
  713.  
  714.     strcat (SockPath, "/");
  715.     SockNamePtr = SockPath + strlen (SockPath);
  716.  
  717.     /* if we are a client send create message to startup window and exit */
  718.     if (GetSockName ())
  719.       {    DO DEBUG("GetSockName says that we are client\n");
  720.         DO DEBUG("SockName '%s'\n", SockName);
  721.         s = MakeClientSocket (1);
  722.         DO DEBUG("Client socket is %d\n", s);
  723.         DO DEBUG("SendCreateMsg()\n");
  724.         if (clienttitle) {
  725.             av[1] = clienttitle;                /* won't work; tries to run it (of course) */
  726.             SendCreateMsg(s, 2, av, loginflag, &shape);
  727.         } else
  728.             SendCreateMsg (s, ac, av, loginflag, &shape);
  729.         close (s);
  730.         DO DEBUG("after SendCreateMsg(), now exit(EXITNORMAL)\n");
  731.         exit (EXITNORMAL);
  732.       }
  733.  
  734.     /* we are the server */
  735.     DO DEBUG("SockName '%s'\n", SockName);
  736.     DO DEBUG("We are server\n");
  737. #ifndef SVR4
  738.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  739.         Msg (errno, "/dev/tty");
  740.     DO DEBUG("opened /dev/tty fd %d\n", DevTty);
  741. #endif
  742.  
  743.     ServerSocket = MakeServerSocket ();
  744.     DO DEBUG("ServerSocket %d\n", ServerSocket);
  745.     s = ServerSocket;
  746.  
  747.     if (fflag)
  748.         flowctl = 1;
  749.     else
  750.     if (nflag)
  751.         flowctl = 0;
  752.  
  753.     if (loginflag == -1)
  754.         loginflag = LOGINDEFAULT;
  755.  
  756.     MakeNewEnv ();
  757.  
  758.     Resetenvonmsg = 1;                    /* cleanup Utmp and tty if abort */
  759.  
  760.     GetTTY (0, &OldMode);
  761.     SetMode (&OldMode, &NewMode);
  762.     SetTTY (0, &NewMode);
  763.  
  764.     InitUtmp ();
  765.  
  766.     /*
  767.      * On some systems, have noticed SIGHUP sent to server whenever a client 
  768.      * terminates, thus terminating the *server* prematurely.
  769.      *
  770.      * Fix this by ignoring SIGHUP on such systems ... (may no longer be needed?)
  771.      */
  772. #ifdef IGNORE_SIGHUP
  773.     signal (SIGHUP, SIG_IGN);            /* ignore SIGUP */
  774. #else
  775.     signal (SIGHUP, SigHup);
  776. #endif
  777.  
  778.     signal (SIGINT, SIG_IGN);            /* we should never see this */
  779.     signal (SIGQUIT, FAbort);            /* quit layers on these 2 signals */
  780.     signal (SIGTERM, FAbort);
  781.     signal (SIGTTIN, SIG_IGN);
  782.     signal (SIGTTOU, SIG_IGN);
  783. #ifdef IRIX
  784.     signal (SIGALRM, ignore_alarm);        /* ignore alarm under IRIX */
  785. #else
  786.     signal (SIGALRM, SIG_IGN);            /* alarm clock used by protocol.c */
  787. #endif
  788.  
  789.     if (Initlink() == 0) {
  790.           exitcode = EXITNOMACLAYERS;        /* return special status code */
  791.         Msg (0, "\n\n  You are not running under MacLayers.");
  792.         DO DEBUG("Initlink() unsuccesful.");
  793.     } else
  794.         DO DEBUG("Initlink() successful.");
  795.  
  796.     /*
  797.      * startup at least one default shell window:
  798.      */
  799.     n = MakeWindow (0, *av, av, (char *)0, loginflag, &shape);
  800.     if (n < 0) {
  801.         SetTTY(0, &OldMode);
  802.         FQuit(EXITABNORMAL);
  803.         /* NOT REACHED */
  804.     }
  805.     DO DEBUG("MakeWindow() == %d", n);
  806.  
  807.     (void) chmod(RealTtyName, 0600);        /* lock out broadcasts */
  808.     Abortonmsg = 0;                            /* don't abort on msg from now on */
  809.     Resetenvonmsg = 0;                        /* no cleanup - messages normal */
  810. #ifdef SVR4
  811.     {
  812.         struct sigaction sa;
  813.  
  814.         sa.sa_handler = SigChld;
  815.         (void) sigemptyset(&sa.sa_mask);
  816.         sa.sa_flags = SA_NOCLDWAIT | SA_SIGINFO;
  817.         (void) sigaction(SIGCHLD, &sa, NULL);
  818.     }
  819. #else
  820. #ifdef SYSV
  821.     signal(SIGCLD, SigChld);
  822. #else
  823.     signal (SIGCHLD, SigChld);
  824. #endif
  825. #endif
  826.     tv.tv_usec = 0;
  827.     tv.tv_sec = 0;                            /* default no timer wanted */
  828.  
  829.     /*
  830.      * now, check for existence of .layersrc file;
  831.      * if it exists, use it:
  832.      */
  833.     sprintf (rc, "%.*s/.layersrc", sizeof(rc)-12, home);
  834.     n = 1 + ReadRc(rc);
  835.  
  836.  
  837.     /* client/Maclayers processing loop */
  838.  
  839.     /* poll .20 secs for new startups */
  840. #define WUSSTARTUP    200000                
  841.     /* stall nonpriority windows .5 seconds when top window I/O active */
  842. #define WUSSTALL    500000
  843.  
  844.     stall = 0;                                /* startout no stalled channels */
  845.     fderr = 0;                                /* startout no error fd's */
  846.  
  847.     while (1)
  848.       {    int            priochan;                /* the top window channel */
  849.  
  850.         priochan = TopChannel();            /* find highest priority channel */
  851.  
  852.         /* check for I/O on all available I/O descriptors */
  853.         r = 1<<0;                            /* always read MacLayers stream */
  854.         r |= 1<<s;                            /* always read server socket */
  855.         w = 0;                                /* initalize to no write tests */
  856.         tv.tv_usec = 0;                        /* default no startup poll */
  857.  
  858.         /* for all active layers set read and write bits as appropriate */
  859.         if (stall)
  860.             stall = 1;                        /* start counting output layers */
  861.         for (n=0; n<MAXPCHAN; n++)
  862.          if ((layer = &World[n])->allocated) /* if layer exists ... */
  863.           {    /* if not yet started or has just terminated ... */
  864.             if (layer->ptymask & fderr)
  865.                 tv.tv_usec = WUSSTARTUP;    /* don't spinloop but wait-a-bit */
  866.             else
  867.                 {    if (layer->kbuff && layer->kbuff->size)
  868.                     /* keyboard input for layer */
  869.                     w |= layer->ptymask;    /* try write to it */
  870.                 /* read layer output unless we're being nice to top window */
  871.                 if (!stall)
  872.                     r |= layer->ptymask;    /* read output from layer */
  873.                 else
  874.                 if (layer->chan == priochan)
  875.                     r |= layer->ptymask;    /* read top priority output */
  876.                 else
  877.                     stall++;                /* indicate something to stall */
  878.                }
  879.             }
  880.  
  881.         if (stall > 1)
  882.             if (!tv.tv_usec)
  883.                 tv.tv_usec = WUSSTALL;        /* set stall timout */
  884.  
  885.         /* process signals before trying select */
  886.         if (GotSignal)
  887.           { SigHandler ();
  888.             continue;
  889.           }
  890.  
  891.         DO DEBUG("Select(r %x, w %x, fderr %x, stall %d, prio %d, us %d)\n",
  892.                     r, w, fderr, stall, priochan, tv.tv_usec);
  893.  
  894.         switch ( select(32, (fd_set *) &r, (fd_set *) &w, (fd_set *) NULL, 
  895.                     tv.tv_usec ? &tv : (struct timeval *) NULL) )
  896.         { case -1:
  897.             /* errno has report */
  898.             if (errno == EINTR)                /* signal delivered or timout */
  899.               { errno = 0;
  900.                 tv.tv_usec = 0;                /* clear timer wait value */
  901.                 fderr = 0;                    /* turn off error stall */
  902.                 stall = 0;                    /* turn off output priority stall */
  903.                 DO DEBUG("select errno EINTR\n");
  904.                 continue;                    /* re-loop */
  905.               }
  906.             Abortonmsg = 1;
  907.             Resetenvonmsg = 1;                /* clean up tty settings */
  908.             DO DEBUG("select errno %d\n", errno);
  909.             Msg (errno, "select");
  910.             /*NOTREACHED*/
  911.  
  912.           case 0:
  913.             /* timeout reached */
  914.             tv.tv_usec = 0;                    /* clear timer wait value */
  915.             stall = 0;                        /* turn off stall */
  916.             fderr = 0;                        /* turn off error stall */
  917.             continue;                        /* re-loop */
  918.  
  919.           default:
  920.             /* a channel has read/write status pending */
  921.             break;
  922.         }
  923.  
  924.         DO DEBUG("after select r %x w %x\n", r, w);
  925.  
  926.         /* handle any signal arriving up during select wait */
  927.         if (GotSignal)
  928.           { SigHandler ();
  929.             continue;
  930.           }
  931.  
  932.         /* if server socket has command process that now */
  933.         if (r & 1 << s)
  934.           {    ReceiveMsg(s);                    /* process client control packet */
  935.             continue;                        /* status may have changed */
  936.           }
  937.  
  938.         /* next process input stream from MacLayers */
  939.         if (r & 1 << 0)
  940.           { ProcessStreamin();                /* key input and control packets */
  941.             continue;                        /* status may have changed */
  942.           }
  943.  
  944.         /* process keyboard input first so output doesn't hold up
  945.         ** keyboard echo and break/interrupt processing
  946.         */
  947.         priochan = TopChannel();            /* find top priority channel */
  948.         stall = 0;                            /* assume no stall needed */
  949.         for (n=0; n<MAXPCHAN; n++)
  950.           if ((layer = &World[n])->allocated)
  951.             if (w & layer->ptymask)
  952.                 while ((kbptr=layer->kbuff)->size)
  953.                   {    /* pass as much keyboard as possible */
  954.                     if (layer->chan == priochan)
  955.                         stall = 1;            /* stall lower priority channels */
  956.                     len = write(layer->ptyfd, &kbptr->text[kbptr->offset],
  957.                                  kbptr->size);
  958.                     DO DEBUG("keyin len %d to chan %d\n", len, layer->chan);
  959.                     if (len <= 0)            /* if no data accepted ... */
  960.                       {    if (errno == EIO)    /* if I/O error indicated ... */
  961.                             fderr |= layer->ptymask; /* wait-a-bit on this */
  962.                         errno = 0;            /* clear errno */
  963.                         break;                /* try again later */
  964.                       }
  965.                     /* some of buffer accepted */
  966.                     kbptr->size -= len;        /* length processed */
  967.                     kbptr->offset += len;    /* bump up offset */
  968.                     if (kbptr->size > 0)    /* not all buffer accepted ... */
  969.                         break;                /* try feed again later */
  970.                     /* see if another buffer chained */
  971.                     if (kbptr->next)
  972.                       {    /* yes, free up current buffer and queue next */
  973.                         layer->kbuff = kbptr->next; /* to next buffer */
  974.                         free(kbptr);    /* free this buffer up */
  975.                       }
  976.                     else
  977.                       {    /* otherwise leave this for next input */
  978.                         kbptr->size = 0;    /* empty buffer */
  979.                         kbptr->offset = 0;    /* refill from the start */
  980.                       }
  981.                   }
  982.  
  983.         /* first process the highest priority channel (top window) */
  984.         if (priochan > 0 && priochan <= MAXPCHAN) /* if valid ... */
  985.           if ((layer = &World[priochan-1])->allocated)
  986.             if (r & layer->ptymask)
  987.               {    /* output to send to top MacLayers window */
  988.                 len = read(layer->ptyfd, buf, IOSIZE);
  989.                 if (len >= 0)                /* if no error ... */
  990.                   {    DO DEBUG("read output len %d chan %d\n", len, layer->chan);
  991.                   }
  992.                 else
  993.                   {    /* We expect EIO error if socket not yet open on other end
  994.                     ** or if process using socket has terminated. We expect
  995.                     ** EWOULDBLOCK also after process terminates.
  996.                     **/
  997.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  998.                                 layer->chan, errno, len);
  999.                     if (errno == EIO || errno == EWOULDBLOCK)
  1000.                         DO DEBUG(" ...anticipated\n");
  1001.                     /* layer not ready or just terminated so wait-a-bit */
  1002.                     fderr |= layer->ptymask;
  1003.                     r &= ~layer->ptymask; /* don't read it again below */
  1004.                     errno = 0;                /* clear errno */
  1005.                   }
  1006.                 if (len > 0)
  1007.                     SendData(layer->chan, buf, len);
  1008.  
  1009.                 if (len >= 0)
  1010.                     /* To keep lower priority channels from hogging the line
  1011.                     ** we delay any output from them until the primary window 
  1012.                     ** has no more data to be sent to it.
  1013.                     */
  1014.                     stall = 1;                /* stall output from others */
  1015.               }
  1016.  
  1017.         /* now pass all available output to MacLayers */
  1018.         if (!stall)
  1019.          for (n=0; n<MAXPCHAN; n++)
  1020.           if ((layer = &World[n])->allocated)
  1021.             if (r & layer->ptymask)
  1022.               {    /* output to send to MacLayers window */
  1023.                 len = read(layer->ptyfd, buf, IOSIZE);
  1024.                 if (len >= 0)                /* if no error ... */
  1025.                   {    DO DEBUG("output chan %d len %d\n", layer->chan, len);
  1026.                   }
  1027.                 else
  1028.                   {    /* We expect EIO error if socket not yet open on other end
  1029.                     ** or if process using socket has terminated. We expect
  1030.                     ** EWOULDBLOCK also after process terminates.
  1031.                     **/
  1032.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  1033.                                 layer->chan, errno, len);
  1034.                     if (errno == EIO || errno == EWOULDBLOCK)
  1035.                       {    DO DEBUG(" ...anticipated\n");
  1036.                       }
  1037.                     /* layer not ready or just terminated so wait-a-bit */
  1038.                     fderr |= layer->ptymask;
  1039.                     errno = 0;                /* clear errno */
  1040.                   }
  1041.                 if (len > 0)
  1042.                     SendData(layer->chan, buf, len);
  1043.               }
  1044.  
  1045.         /* handle signals again */
  1046.         if (GotSignal)
  1047.             SigHandler ();
  1048.  
  1049.       } /* end while (1) */
  1050.  
  1051.     /* NOT REACHED */
  1052.  
  1053. } /* main() */
  1054.  
  1055.                     /* ReceiveQuit() - MacLayers sends Quit packet */
  1056.  
  1057. void
  1058. ReceiveQuit()
  1059. {
  1060.     /* We completely quit layers cancelling all active processes */
  1061.     DO DEBUG("ReceiveQuit()\n");
  1062.     FQuit(EXITNORMAL);                    /* normal termination */
  1063.     /* NOT REACHED */
  1064.  
  1065. } /* ReceiveQuit() */
  1066.  
  1067.  
  1068.                 /* ReceiveNew() - MacLayers requests a new shell layer */
  1069.  
  1070. void
  1071. ReceiveNew(chanid, shape)
  1072. int        chanid;                                /* channel for new shell layer */
  1073. struct Shape *shape;                        /* shape for new channel */
  1074. {
  1075.     static int MakeWindow();
  1076.  
  1077.     DO DEBUG("ReceiveNew(%d)\n", chanid);
  1078.     (void) MakeWindow (chanid, *ShellArgs, ShellArgs,
  1079.                     (char *) 0, loginflag, shape);
  1080.  
  1081. } /* ReceiveNew() */
  1082.  
  1083.  
  1084.                 /* ReceiveDelete() - MacLayers has removed a layer */
  1085. void
  1086. ReceiveDelete(chanid)
  1087. int        chanid;                                /* channel which was deleted */
  1088. {
  1089.     static void KillWindow();
  1090.     struct Layer *layer;                    /* layer pointer */
  1091.  
  1092.     /* validate channel */
  1093.     DO DEBUG("ReceiveDelete(%d)\n", chanid);
  1094.     if (chanid <= 0 || chanid > MAXPCHAN)
  1095.         return;                                /* ignore invalid channel */
  1096.  
  1097.     /* if this layer active then kill it off, else ignore request */
  1098.     layer = &World[chanid-1];                /* locate target layer */
  1099.     if (layer->allocated)
  1100.         KillWindow(layer);
  1101.  
  1102. } /* ReceiveDelete() */
  1103.     
  1104.     
  1105.         /* ReceiveSignal() - send signal to layer's process group */
  1106.  
  1107. void
  1108. ReceiveSignal(chanid, signal)
  1109. int            chanid;                            /* layer's channel */
  1110. int            signal;                            /* signal.h signal ID */
  1111. {
  1112.     struct Layer *layer;                    /* layer pointer */
  1113.  
  1114.     DO DEBUG("ReceiveSignal(%d,%d)\n", chanid, signal);
  1115.     /* verify channel */
  1116.     if (chanid <= 0 || chanid > MAXPCHAN)
  1117.         return;                                /* ignore invalid channel */
  1118.  
  1119.     /* if this layer is active send the signal to the process group */
  1120.     layer = &World[chanid-1];                /* locate target layer */
  1121.     if (layer->allocated && layer->lpid)
  1122.         KillPG(layer, signal);
  1123.  
  1124. } /* ReceiveSignal() */
  1125.  
  1126.  
  1127.                 /* ReceiveReshape() - windowsize and location updated */
  1128. void
  1129. ReceiveReshape(chanid, shape)
  1130. int                chanid;                    /* channel having shape */
  1131. struct Shape    *shape;                    /* shape structure */
  1132. {
  1133.     struct Layer *layer;                /* layer pointer */
  1134.  
  1135.     DO DEBUG("ReceiveReshape(%d)\n", chanid);
  1136.  
  1137.     /* verify channel */
  1138.     if (chanid <= 0 || chanid > MAXPCHAN)
  1139.         return;                                /* ignore invalid channel */
  1140.  
  1141.     /* if this layer is active then reshape it's window */
  1142.     layer = &World[chanid-1];                /* locate target layer */
  1143.     if (layer->allocated && layer->lpid)
  1144.       {    layer->shape = *shape;                /* install as our new shape */
  1145.         SetWindowSize(layer);                /* udpate the O/S window info */
  1146.       }
  1147.  
  1148. } /* ReceiveReshape() */
  1149.  
  1150.  
  1151.             /* SetWindowSize() - tell O/S about new window size */
  1152.  
  1153. static void
  1154. SetWindowSize(layer)
  1155. struct Layer    *layer;                    /* layer to resize */
  1156. {
  1157. #ifdef TIOCSWINSZ
  1158.     struct    winsize    wsize;                /* window size structure */
  1159.     int            retcode;                /* ioctl return code */
  1160.  
  1161.     wsize.ws_col = layer->shape.wchars; /* character width */
  1162.     wsize.ws_row = layer->shape.wlines; /* window height */
  1163.     wsize.ws_xpixel = 0;                /* necessary? */
  1164.     wsize.ws_ypixel = 0;
  1165.     /* update O/S window state */
  1166.     retcode = ioctl(layer->ptyfd, TIOCSWINSZ, &wsize);
  1167.     DO DEBUG("SetWindowSize(chan %d) col %d, row %d iotcl() = %d\n",
  1168.             layer->chan, layer->shape.wchars, layer->shape.wlines,
  1169.             retcode);
  1170.  
  1171.     retcode = ioctl(layer->ptyfd, TIOCGWINSZ, &wsize);
  1172.     DO DEBUG("TIOCGWINSZ: col %d, row %d iotcl() = %d\n",
  1173.             wsize.ws_col, wsize.ws_row, retcode);
  1174.  
  1175. #ifdef SIGWCHG
  1176.     /* inform process group that control terminal has altered size */
  1177.     KillPG(layer, SIGWCHG);
  1178. #endif
  1179.  
  1180. #endif
  1181. }  /* SetWindowSize() */
  1182.  
  1183.  
  1184.                 /* ReceiveData() - received keyboard input for layer */
  1185. void
  1186. ReceiveData(chanid, buff, cnt)
  1187. int        chanid;                            /* channel receiving input */
  1188. char    *buff;                            /* buffer containing data */
  1189. int        cnt;                            /* count of data bytes */
  1190. {
  1191.     struct Layer *layer;                /* layer pointer */
  1192.     struct Kbuff *kb;                    /* keybuff pointer */
  1193.  
  1194.     DO DEBUG("ReceiveData(%d, '%.*s')\n", chanid, cnt, buff);
  1195.     /* verify channel */
  1196.     if (chanid <= 0 || chanid > MAXPCHAN)
  1197.         return;                                /* ignore invalid channel */
  1198.     layer = &World[chanid-1];                /* locate target layer */
  1199.  
  1200.     /* add character stream to layer's input buffers for main loop processing */
  1201.     for (kb=layer->kbuff; kb->next; kb=kb->next); /* find oldest buffer */
  1202.     while (cnt--)
  1203.       {    
  1204.         /* if current buffer full then chain in a new one */
  1205.         if (kb->offset+kb->size >= IOSIZE)
  1206.           { kb->next = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  1207.             kb = kb->next;                    /* base new keybuff */
  1208.             kb->next = NULL;                /* no next yet */
  1209.             kb->size = 0;                    /* this character is first */
  1210.             kb->offset = 0;                    /* at zero offset */
  1211.           }
  1212.  
  1213.         /* add new character to the end of this buffer */
  1214.         kb->text[kb->offset+kb->size++] = *buff++; /* insert at end of data */
  1215.       }
  1216.  
  1217. } /* ReceiveData() */
  1218.  
  1219.  
  1220.  
  1221.                     /* InitWorld() - initialize layer structures */
  1222.  
  1223. static void
  1224. InitWorld()
  1225. {
  1226.     struct Layer *layer;                /* layer pointer */
  1227.     struct Kbuff *kb;                    /* keybuff pointer [UNUSED] */
  1228.     int        i;                            /* work variable */
  1229.  
  1230.     for (i=0; i<MAXPCHAN; i++)
  1231.       {    layer = &World[i];                /* point to layer */
  1232.         layer->chan = i+1;                /* channel ID */
  1233.         layer->allocated = 0;            /* does not exist yet */
  1234.         layer->lpid = 0;                /* head process */
  1235.         layer->ptyfd = 0;                /* no pseduo pty yet */
  1236.         layer->ptymask = 0;                /* no pty mask yet */
  1237.         layer->slot = 0;                /* no Utmp slot */
  1238.         ClearShape(&layer->shape);        /* clear shape structure */
  1239.  
  1240.         /* allocate the primary input keybuffer for this layer */
  1241.         layer->kbuff = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  1242.         layer->kbuff->next = NULL;        /* no next buffer */
  1243.         layer->kbuff->size = 0;            /* no data in buffer */
  1244.         layer->kbuff->offset = 0;        /* start filling at front */
  1245.  
  1246.       } /* end for layer scan */
  1247.  
  1248. } /* InitWorld() */
  1249.  
  1250.  
  1251.                     /* clearshape() - initialize shape structure */
  1252.  
  1253. static void
  1254. ClearShape(shape)
  1255. struct Shape    *shape;                    /* shape structure pointer */
  1256. {
  1257.     shape->worigv = 0;                    /* default window position */
  1258.     shape->worigh = 0;
  1259.     shape->wlines = 0;                    /* default size */
  1260.     shape->wchars = 0;
  1261.     shape->wfont = 0;                    /* default font size */
  1262.     shape->wattr = 0;                    /* no attributes */
  1263.  
  1264. } /* clearshape() */
  1265.  
  1266.  
  1267.                     /* SigHandler() - process signals */
  1268.  
  1269. void
  1270. SigHandler ()
  1271. {
  1272.     static void    DoWait();
  1273.  
  1274.     DO DEBUG("GotSignal()\n");
  1275.     while (GotSignal)
  1276.       { GotSignal = 0;
  1277.         DoWait ();        /* handle dead or stopped children processes */
  1278. #ifdef SYSV
  1279.     signal(SIGCLD, SigChld);
  1280. #endif
  1281.       }
  1282. }
  1283.  
  1284. #ifdef SVR4
  1285. static void
  1286. SigChld(int sn, siginfo_t * si, void * uc)
  1287. {
  1288.     int i;
  1289.     struct Layer *layer;
  1290.  
  1291.     if (si == NULL) {
  1292.         DO DEBUG("SigChld: OOPS! no siginfo\n");
  1293.         return;
  1294.     }
  1295.     DO DEBUG("code %d errno %d pid %d\n",
  1296.         si->si_code, si->si_errno, si->si_pid);
  1297.  
  1298.     if (si->si_code == CLD_STOPPED) {
  1299.         (void) sigsend(P_PID, si->si_pid, SIGCONT);
  1300.         return;
  1301.     }
  1302.     for (i = 0; i < MAXPCHAN; i++) {
  1303.         if ((layer = &World[i])->lpid == si->si_pid) {
  1304.             DO DEBUG("dead session reaped\n");
  1305.             layer->lpid = (-layer->lpid);       /* Mark as dead */
  1306.             GotSignal = 1;
  1307.         }
  1308.     }
  1309. }
  1310.  
  1311. #else
  1312. static SIGTYPE
  1313. SigChld ()
  1314. {
  1315.     DO DEBUG("SigChld()\n");
  1316.     /* flag child process is stopped or dead */
  1317.     GotSignal = 1;
  1318. }
  1319. #endif
  1320.  
  1321. static SIGTYPE
  1322. SigHup ()
  1323. {
  1324.     DO DEBUG("SigHup()\n");
  1325.     /* Detach (0); */
  1326.     FQuit(EXITSIGHUP);            /* stop all processes */
  1327.     /* NOT REACHED */
  1328. }
  1329.  
  1330.     /* DoWait() -  send SIGCONT to stopped windows, Free dead process windows */
  1331.  
  1332. #ifdef SVR4
  1333. static void
  1334. DoWait()
  1335. {
  1336.     static void    KillWindow();
  1337.  
  1338.     int     i;
  1339.     register struct Layer *layer;
  1340.  
  1341.     DO DEBUG("DoWait()\n");
  1342.     for (i = 0; i < MAXPCHAN; i++) {
  1343.         if ((layer = &World[i])->lpid < 0) {
  1344.             layer->lpid = (-layer->lpid);
  1345.             DO DEBUG("kill dead process window %d\n", layer->chan);
  1346.             KillWindow(layer);
  1347.             SendDelete(layer->chan);    /* tell MacLayers layer is dead */
  1348.         }
  1349.     }
  1350. } /* DoWait() */
  1351. #else
  1352. static void
  1353. DoWait()
  1354. {
  1355.     static void    KillWindow();
  1356.  
  1357.     register pid;
  1358.     register struct Layer *layer;
  1359.     union wait wstat; 
  1360.     int        i;
  1361.  
  1362.     DO DEBUG("DoWait()\n");
  1363.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0)
  1364.         /* dead or stopped child process found */
  1365.         for (i=0; i<MAXPCHAN; i++)
  1366.             if ((layer = &World[i])->lpid == pid)
  1367.               { if (WIFSTOPPED (wstat))
  1368.                   {    /* stopped process so restart it */
  1369.                     /*** DO WE REALLY NEED TO DO THIS? ***/
  1370.                     DO DEBUG("killpg(, SIGCONT)\n");
  1371.                     KillPG(layer, SIGCONT);
  1372.                   }
  1373.                 else
  1374.                   {    /* remove dead process's layer */
  1375.                     DO DEBUG("kill dead process window %d\n", layer->chan);
  1376.                      KillWindow (layer);
  1377.                     /* tell MacLayers layer is dead */
  1378.                     SendDelete(layer->chan);
  1379.                   }
  1380.               }
  1381.  
  1382. } /* DoWait() */
  1383. #endif
  1384.  
  1385.  
  1386.                 /* KillPG() - send signal to layer's process group */
  1387.  
  1388. static void
  1389. KillPG(layer, signal)
  1390. struct Layer    *layer;                    /* layer to signal */
  1391. int                signal;                    /* signal to send */
  1392. {
  1393.     int            retcode;                /* work variable */
  1394.     int            pgrp;                    /* process group for layer */
  1395.     int            tgrp;                    /* terminal control process group */
  1396.  
  1397.     DO DEBUG("KillPG(%d, sig %d)\n", layer->chan, signal);
  1398.  
  1399.     if (layer->lpid) {
  1400. #ifdef SVR4
  1401.         pgrp = getpgid (layer->lpid);   /* get process group */
  1402.         DO DEBUG("getpgid() = %d\n", pgrp);
  1403.         if (pgrp != -1) {
  1404.             retcode = sigsend(P_PGID, pgrp, signal); /* signal it */
  1405.             DO DEBUG("sigsend() = %d\n", retcode);
  1406.         }
  1407. #else
  1408. #if defined(AUX) || defined(AIX)
  1409.         /* 
  1410.          * getpgrp does not get anyone else's pgrp on A/UX. You could
  1411.          * find this by mucking in the kernel, but I'm not willing to
  1412.          * go that far yet.
  1413.          */
  1414.         pgrp = layer->lpid;
  1415. #else
  1416.           pgrp = getpgrp(layer->lpid);    /* get process group */
  1417.         DO DEBUG("getpgrp() = %d\n", pgrp);
  1418.         if (pgrp != -1)
  1419.           {    retcode = killpg(pgrp, signal);    /* signal it */
  1420.             DO DEBUG("killpg() = %d\n", retcode);
  1421.           }
  1422.  
  1423.         /* 
  1424.         ** In order to accomplish job control, csh and derived shells
  1425.         ** create a new terminal control group whenever they run a command.
  1426.         ** Thus the above code failed to forward SIGINT to such commands.
  1427.         ** (Csh would get it but just ignore it.) Thus the following code.
  1428.         */ 
  1429.  
  1430.         /* forward SIGINT to the terminal control group also */
  1431.         /* (This should probably be done for ALL Signals, but at present is not) */
  1432.         if (signal == SIGINT)
  1433.           {    retcode = ioctl(layer->ptyfd, TIOCGPGRP, &tgrp);
  1434.             DO DEBUG("ioctl(ptyfd,TIOCGPGRP) termcntlgrp %d, retcode = %d\n",
  1435.                             tgrp, retcode);
  1436.             /* but only if not the same process group */
  1437.             if (retcode != -1 && tgrp != pgrp)
  1438.               {    retcode = killpg(tgrp, signal);    /* signal it */
  1439.                 DO DEBUG("killpg(%d) = %d\n", tgrp, retcode);
  1440.                 }
  1441.           }
  1442. #endif
  1443. #endif
  1444.       }
  1445.  
  1446. } /* KillPG() */
  1447.  
  1448.  
  1449.                 /* KillWindow() - remove a layer from the system */
  1450.  
  1451. /* Note: This function does NOT tell MacLayers about the dead layer */
  1452.  
  1453. static void
  1454. KillWindow (layer)
  1455. struct Layer *layer;
  1456. {
  1457.     struct Kbuff    *kb;                /* work buffer free pointer */
  1458.  
  1459.     if (layer->allocated)
  1460.       {                                 /* SHOULD THIS BE SIGKILL or SIGHUP ??? */
  1461.         if (layer->lpid)                /* if layer process started ... */
  1462.           {    KillPG(layer, SIGHUP);        /* kill processes */
  1463.             layer->lpid = 0;            /* clear pid field */
  1464.           }
  1465.         RemoveTtyFromUtmp(layer);
  1466.         (void) chmod(layer->tty, 0666);
  1467.         (void) chown(layer->tty, 0, 0);
  1468.         close(layer->ptyfd);
  1469.         DO DEBUG("chmod/chown %s, SendDelete(%d)\n",layer->tty, layer->chan);
  1470.  
  1471.         ClearShape(&layer->shape);        /* reset the shape structure */
  1472.         /* free all keybuffers but the last one and reprime it */
  1473.         for (kb=layer->kbuff; kb->next; kb=layer->kbuff) {
  1474.             layer->kbuff = kb->next;
  1475.             free(kb);                    /* free input buffers */
  1476.         }
  1477.         kb->size = 0;                    /* empty buffer */
  1478.         kb->offset = 0;                    /* start refill from front */
  1479.         layer->allocated = 0;            /* window no longer allocated */
  1480.       }
  1481.  
  1482. } /* KillWindow() */
  1483.  
  1484.  
  1485.                     /* FAbort() - signal catcher for quitting */
  1486. static SIGTYPE
  1487. FAbort()
  1488. {
  1489.     DO DEBUG("FAbort()\n");
  1490.     FQuit (EXITSIGQUIT);                /* quit with error exit */
  1491.  
  1492. } /* FAbort() */
  1493.  
  1494.  
  1495.                     /* FQuit() - terminate layers */
  1496. void
  1497. FQuit(exitcode)
  1498. int        exitcode;
  1499. {
  1500.     int            i;
  1501.  
  1502. #ifndef POSIXTTY
  1503.     static void SetTTY();
  1504. #endif
  1505.  
  1506.  
  1507.     DO DEBUG("FQuit(%d)\n",exitcode);
  1508.     for (i=0; i<MAXPCHAN; i++)
  1509.         KillWindow(&World[i]);            /* kill all windows */
  1510.  
  1511.     DO DEBUG("SendQuit()\n");
  1512.     SendQuit();                            /* tell MacLayers to exit layers mode */
  1513.     SetTTY (0, &OldMode);
  1514.     if (RealTtyMode)
  1515.         (void) chmod(RealTtyName, RealTtyMode);    /* restore mode */
  1516.     RestoreRealUtmp();
  1517.     FinitTerm ();
  1518.     sleep(2);                            /* wait for port to reset */
  1519.     fputs ("[layers terminated]\n", stdout);
  1520.  
  1521.     exit (exitcode);
  1522.  
  1523. } /* FQuit() */
  1524.  
  1525.  
  1526.         /* MakeWindow() - create new layer */
  1527. static int
  1528. MakeWindow (chan, prog, args, dir, lflag, shape)
  1529. int    chan;        /* zero or channel to use for window */
  1530. char    *prog;
  1531. char     **args;
  1532. char    *dir;
  1533. int    lflag;        /* one if this to be logged in */
  1534. struct Shape *shape;    /* shape to use for window */
  1535. {
  1536.     void Msg();
  1537.     static void SendErrorMsg(), execvpe();
  1538. #ifndef POSIXTTY
  1539.     static void SetTTY();
  1540. #endif
  1541.     static int OpenPTY();
  1542.  
  1543.     register struct Layer *layer;
  1544.     register char **cp;                /* [UNUSED] */
  1545.     register f;
  1546.     int tf;
  1547.     int mypid;
  1548.     char ebuf[10];
  1549.  
  1550.     DO DEBUG("MakeWindow(%d, %s, %s, dir %s, ",
  1551.                 chan, prog, args[0], dir ? dir : "(none)");
  1552.     DO DEBUG("login %d\n", lflag);
  1553.     DO DEBUG("    origv %d, origh %d, lines %d, chars %d, ",
  1554.                 shape->worigv, shape->worigh, shape->wlines, shape->wchars);
  1555.     DO DEBUG("font %d, attr 0x%x\n", shape->wfont, shape->wattr);
  1556.                     
  1557.     if ((f = OpenPTY ()) == -1)
  1558.       { Msg (0, "No more PTYs.");
  1559.         return ( -1 );
  1560.       }
  1561.  
  1562.     /* 
  1563.      * If channel not given,
  1564.      *     obtain one from MacLayers:
  1565.      */
  1566.     if (chan == 0)
  1567.       {    chan = SendNew(shape);                /* try to get free window */
  1568.         if (chan == 0)
  1569.             {    Msg (0, "No more windows.");
  1570.             return ( -1 );
  1571.             }
  1572.         DO DEBUG("SendNew() == %d\n", chan);
  1573.       }
  1574.  
  1575.     /* verify channel */
  1576.     if (chan <= 0 || chan > MAXPCHAN)
  1577.       {    Msg(0, "Invalid channel %d.", chan);
  1578.         return ( -1 );
  1579.       }
  1580.  
  1581.     /* login this window if it's layer #1 */
  1582.     if (chan == 1)
  1583.         lflag = 1;
  1584.                     
  1585.     if (lflag == -1)
  1586.         lflag = loginflag;
  1587.     
  1588. #ifdef USRLIMIT
  1589.     /*
  1590.      *    Count current number of users, and if logging windows in,
  1591.      */
  1592.     if (lflag == 1)
  1593.       { (void) lseek (utmpf, 0, 0);
  1594.         UserCount = 0;
  1595.         while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
  1596.           { if (utmpbuf.ut_name[0] != '\0')
  1597.                 UserCount++;
  1598.           }
  1599.         if (UserCount >= USRLIMIT)
  1600.           {    /* MUST NOT ISSUE MESSAGE SINCE IT GETS INTERSPERSED WITH
  1601.             ** PACKET SENT INDICATING CURRENT INPUT WINDOW!! THIS
  1602.             ** CAUSES IT TO BE CORRUPTED.  (1.00 Bug Fix 001)
  1603.             */
  1604.             /* Msg (0, "User limit reached.  Window will not be logged in."); */
  1605.             lflag = 0;
  1606.           }
  1607.       }
  1608. #endif USRLIMIT
  1609.  
  1610.     layer = &World[chan-1];                    /* find layer structure */
  1611.     layer->shape = *shape;                    /* install new window shape */
  1612.  
  1613.     /* ??? What do we do if layer is still active as far as we're concerned? */
  1614.     if (layer->allocated)
  1615.       {    DO DEBUG("??? newlayer not free !!!\n");
  1616.         KillWindow(layer);                    /* kill off old layer */
  1617.         SendDelete(layer->chan);            /* kill window back off */
  1618.         Msg (0, "Makewindow error: Duplicate active layer %d.", chan);
  1619.         return ( -1 );                        /* return failed */
  1620.       }
  1621.  
  1622.     layer->allocated = 1;                    /* show layer now in use */
  1623.     BuildTitle(chan, prog, args);            /* install window title */
  1624.  
  1625. #ifdef SYSV
  1626.     (void) fcntl(f, F_SETFL, O_NDELAY);
  1627. #else
  1628.     (void) fcntl(f, F_SETFL, FNDELAY);
  1629. #endif
  1630.     layer->ptyfd = f;                        /* pseudo pty for task's I/O */
  1631.     layer->ptymask = 1<<f;                    /* set pty device mask */
  1632.     strncpy (layer->cmd, Filename (args[0]), MAXSTR-1);
  1633.     layer->cmd[MAXSTR-1] = '\0';
  1634.     strncpy (layer->tty, TtyName, MAXSTR-1);
  1635.     DO DEBUG("forking %s, tty %s, ptyfd %d, mask %x\n",
  1636.                 layer->cmd, layer->tty, layer->ptyfd, layer->ptymask);
  1637.     (void) chown (TtyName, getuid (), getgid ());
  1638.     if (lflag == 1) {
  1639.        layer->slot = SetUtmp(TtyName, chan == 1, World[0].lpid); 
  1640.         if (chan == 1 && RealTtyMode)
  1641.             /* set to original tty umask */
  1642.             (void) chmod(TtyName, RealTtyMode);
  1643.         else
  1644.             /* force to this mode */
  1645.             (void) chmod(TtyName, TtyMode);
  1646.       }
  1647.     else
  1648.       { layer->slot = -1;
  1649.         /* do not allow any other user access to this device */
  1650.         (void) chmod (TtyName, 0600);
  1651.       }
  1652.     switch (layer->lpid = fork ())
  1653.     { case -1:
  1654.         Msg (errno, "fork");
  1655.         layer->lpid = 0;                    /* clear pid field */
  1656.         return ( -1 );                        /* return failed */
  1657.  
  1658.       case 0:
  1659.         signal (SIGHUP, SIG_DFL);
  1660.         signal (SIGINT, SIG_DFL);
  1661.         signal (SIGQUIT, SIG_DFL);
  1662.         signal (SIGTERM, SIG_DFL);
  1663.         signal (SIGTTIN, SIG_DFL);
  1664.         signal (SIGTTOU, SIG_DFL);
  1665.         signal (SIGALRM, SIG_DFL);
  1666.         setuid (getuid ());
  1667.         setgid (getgid ());
  1668.         if (dir && chdir (dir) == -1)
  1669.           { SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  1670.             exit (EXITABNORMAL);
  1671.           }
  1672. #if defined(SVR4) || defined(AUX) || defined(AIX)
  1673.         mypid = setsid();
  1674. #else
  1675.         mypid = getpid ();
  1676.         (void) setpgrp (0, mypid);
  1677.         ioctl (DevTty, TIOCNOTTY, (char *)0);
  1678. #endif
  1679.         if ((tf = open (TtyName, O_RDWR)) == -1)
  1680.           { SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  1681.             exit (EXITABNORMAL);
  1682.           }
  1683. #ifdef SVR4
  1684.         (void) ioctl(tf, I_PUSH, "ptem");
  1685.         (void) ioctl(tf, I_PUSH, "ldterm");
  1686.         if(mypid > 0 && tcsetpgrp(tf, mypid) < 0) {
  1687.             DO DEBUG("tcsetpgrp(): %s\n", strerror(errno));
  1688.         }
  1689. #endif
  1690.         DO DEBUG("Now in new process\n");
  1691.         fflush(stdout);
  1692.         fflush(stderr);
  1693.         (void) dup2 (tf, 0);
  1694.         (void) dup2 (tf, 1);
  1695.         (void) dup2 (tf, 2);
  1696.         for (f = getdtablesize () - 1; f > 2; f--)
  1697.             close (f);
  1698.         ioctl (0, TIOCSPGRP, &mypid);
  1699.         SetTTY (0, &OldMode);
  1700.  
  1701.           {    struct    winsize    wsize;        /* window size structure */
  1702.             int            retcode;        /* ioctl return code */
  1703.  
  1704.             wsize.ws_col = layer->shape.wchars; /* character width */
  1705.             wsize.ws_row = layer->shape.wlines; /* window height */
  1706.             wsize.ws_xpixel = 0;                /* necessary? */
  1707.             wsize.ws_ypixel = 0;
  1708.             /* update O/S window state */
  1709.             retcode = ioctl(0, TIOCSWINSZ, &wsize);
  1710.           }
  1711.         (void) umask(Oumask);            /* restore user's original umask */
  1712.         NewEnv[2] = MakeTermcap(layer->shape.wlines, layer->shape.wchars);
  1713.         sprintf (ebuf, "LAYER=%d", chan);
  1714.         NewEnv[3] = ebuf;
  1715.         execvpe (prog, args, NewEnv);
  1716.         printf("%s: cannot exec %s: %s", myname, prog, sys_errlist[errno]);
  1717.         exit (EXITABNORMAL);
  1718.     }
  1719.  
  1720.     DO DEBUG("MakeWindow() returning channel %d\n", chan);
  1721.     return ( chan );
  1722.  
  1723. } /* MakeWindow() */
  1724.  
  1725. static void
  1726. execvpe (prog, args, env)
  1727. char *prog, **args, **env;
  1728. {
  1729.     register char *path, *p;
  1730.     char buf[1024];
  1731.     char *shargs[MAXARGS+1];
  1732.     register i;
  1733.     register eaccess = 0;
  1734.  
  1735.     if (prog[0] == '/')
  1736.         path = "";
  1737.     else
  1738.     if ((path = getenv ("PATH")) == 0)
  1739.         path = DefaultPath;
  1740.     do
  1741.       { p = buf;
  1742.         while (*path && *path != ':')
  1743.             *p++ = *path++;
  1744.         if (p > buf)
  1745.             *p++ = '/';
  1746.         strcpy (p, prog);
  1747.         if (*path)
  1748.             ++path;
  1749.         execve (buf, args, env);
  1750.         switch (errno)
  1751.         { case ENOEXEC:
  1752.             shargs[0] = DefaultShell;
  1753.             shargs[1] = buf;
  1754.             for (i = 1; shargs[i+1] = args[i]; ++i);
  1755.             execve (DefaultShell, shargs, env);
  1756.             return;
  1757.  
  1758.           case EACCES:
  1759.             eaccess = 1;
  1760.             break;
  1761.  
  1762.           case ENOMEM: case E2BIG: case ETXTBSY:
  1763.             return;
  1764.  
  1765.         } /* end switch */
  1766.  
  1767.     } while (*path);
  1768.  
  1769.     if (eaccess)
  1770.         errno = EACCES;
  1771.  
  1772. } /* execvpe() */
  1773.  
  1774.  
  1775.                 /* BuildTitle() - create and install window title */
  1776.  
  1777. static void
  1778. BuildTitle(chan, prog, args)
  1779. int            chan;                        /* channel for title */
  1780. char        *prog;                        /* program being executed */
  1781. char        **args;                        /* arg list */
  1782. {
  1783.     int        i;                            /* arg scan index */
  1784.     char    buff[1024];                    /* super huge title buffer */
  1785.  
  1786.     /* skip any leading "/bin/" */
  1787.     if (strncmp(prog, "/bin/", 5) == 0)
  1788.         strcpy(buff, prog+5);            /* leave /bin off */
  1789.     else if (strncmp(prog, "/usr/bin/", 9) == 0)
  1790.         strcpy(buff, prog+9);            /* leave /usr/bin off */
  1791.     else
  1792.         strcpy(buff, prog);                /* start with program name */
  1793.  
  1794.     /* add all aguments but stop if option ("-") seen */
  1795.     for (i=1; args[i] && args[i][0] != '-'; i++)
  1796.       {    strcat(buff, " ");                /* delimiter */
  1797.         strcat(buff, args[i]);            /* add next parameter */
  1798.       }
  1799.  
  1800.     SendTitle(chan, buff, strlen(buff)); /* set new window title */
  1801.  
  1802. } /* BuildTitle() */
  1803.  
  1804.  
  1805. #ifdef sequent
  1806. static int
  1807. OpenPTY ()
  1808. {
  1809.     char *m, *s;
  1810.     register f;
  1811.  
  1812.     f = getpseudotty (&s, &m);
  1813.     strncpy (PtyName, m, sizeof (PtyName));
  1814.     strncpy (TtyName, s, sizeof (TtyName));
  1815.     ioctl (f, TIOCFLUSH, (char *)0);
  1816.     return (f);
  1817. }
  1818.  
  1819. #else
  1820. #ifdef IRIX
  1821. static
  1822. OpenPTY ()
  1823. {
  1824.     int f;
  1825.     char *tn;
  1826.  
  1827.     if ((tn = _getpty(&f, O_RDWR, TtyMode, 0)) != 0) {
  1828.         strncpy(TtyName, tn, sizeof (TtyName));
  1829.         return f;
  1830.     } else
  1831.         return -1;
  1832. }
  1833. #else
  1834. #ifdef SVR4
  1835. static int
  1836. OpenPTY()
  1837. {
  1838.     extern char *ptsname();
  1839.     int fdm;
  1840.  
  1841.     if ((fdm = open("/dev/ptmx", O_RDWR)) < 0)
  1842.         return (-1);
  1843.     grantpt(fdm);
  1844.     unlockpt(fdm);
  1845.     (void) strcpy(TtyName, ptsname(fdm));
  1846.     return fdm;
  1847. }
  1848. #else
  1849. static
  1850. OpenPTY ()
  1851. {
  1852.     register char *p, *l, *d;
  1853.     register i, f, tf;
  1854.  
  1855.     strcpy (PtyName, PtyProto);
  1856.     strcpy (TtyName, TtyProto);
  1857.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i);
  1858. #ifndef SEQUENT
  1859.     for (l = "pqrstuvwxyzPQRST"; *p = *l; ++l)
  1860.       { for (d = "0123456789abcdef"; p[1] = *d; ++d)
  1861. #else
  1862.     for (l = "pqrstuvwPQRSTUVW"; *p = *l; ++l)
  1863.       { for (d = "0123456789abcdef"; p[1] = *d; ++d)
  1864. #endif
  1865.           { if ((f = open (PtyName, O_RDWR)) != -1)
  1866.               { TtyName[i] = p[0];
  1867.                 TtyName[i+1] = p[1];
  1868. #ifndef AUX
  1869.                 if ((tf = open (TtyName, O_RDWR)) != -1)
  1870.                   { close (tf);
  1871.                     return f;
  1872.                   }
  1873. #else
  1874.             /* 
  1875.              * On A/UX, opening and closing the slave pty will result
  1876.              * in the master getting nothing but EIO. Thus, we delay
  1877.              * opening the slave pty until we're really ready for it.
  1878.              */
  1879.             return f;
  1880. #endif
  1881.                 close (f);
  1882.               }
  1883.           }
  1884.       }
  1885.  
  1886.     return -1;
  1887.  
  1888. } /* OpenPTY() */
  1889.  
  1890. #endif /* NOT SVR4 */
  1891. #endif /* NOT IRIX */
  1892. #endif /* NOT sequent */
  1893.  
  1894. #ifdef POSIXTTY
  1895.  
  1896. static
  1897. SetMode(op, np)
  1898. struct termios *op, *np;
  1899. {
  1900.     *np = *op;
  1901.     if (flowctl)
  1902.         np->c_iflag = BRKINT|IGNPAR|IXON|IXOFF;
  1903.     else
  1904.         np->c_iflag = BRKINT|IGNPAR;
  1905.     np->c_oflag = 0;        /* No special output processing */
  1906.     /* leave cflag alone, it has the baud rate etc. */
  1907.     np->c_lflag = 0;        /* should put terminal in raw mode ... */
  1908.     np->c_cc[VMIN] = 1;
  1909.     np->c_cc[VTIME] = 0;
  1910. }
  1911.  
  1912. #else
  1913.  
  1914. #ifdef USE_TERMIO
  1915. static void
  1916. SetTTY (fd, mp)
  1917. struct termio *mp;
  1918. {     
  1919.     ioctl (fd, TCSETAF, mp);
  1920.  
  1921. } /* SetTTY() */
  1922.  
  1923. static void
  1924. GetTTY (fd, mp)
  1925. struct termio *mp;
  1926. {      
  1927.     ioctl (fd, TCGETA, mp);
  1928.  
  1929. } /* GetTTY() */
  1930.  
  1931. static 
  1932. SetMode (op, np)
  1933. struct termio *op, *np;
  1934. {
  1935.     *np             = *op;
  1936.     np->c_iflag     = 0;        /* no input processing */
  1937.     np->c_oflag    &= ~OPOST;    /* no output processing */
  1938.     np->c_lflag     = NOFLSH;    /* don't flush I/O on quit/swtch/intrpt */
  1939.     np->c_cc[VMIN]  = 1;        /* read ends of this many chars */
  1940.     np->c_cc[VTIME] = 0;        /*  or this many .1 seconds after char recieved */
  1941.  
  1942. } /* SetMode() */
  1943.  
  1944. #else
  1945.  
  1946. static void
  1947. SetTTY (fd, mp)
  1948. int    fd;
  1949. struct mode *mp;
  1950. {
  1951.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  1952.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  1953.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  1954.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  1955.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  1956.  
  1957. } /* SetTTY() */
  1958.  
  1959. static void
  1960. GetTTY (fd, mp)
  1961. int    fd;
  1962. struct mode *mp;
  1963. {
  1964.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  1965.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  1966.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  1967.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  1968.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  1969.  
  1970. } /* GetTTY() */
  1971.  
  1972.  
  1973. static
  1974. SetMode (op, np)
  1975. struct mode *op, *np;
  1976. {
  1977.     *np = *op;
  1978. #if 1
  1979.     if (flowctl)
  1980.       {    np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1981.         np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1982.       }
  1983.     else
  1984.         np->m_ttyb.sg_flags = RAW | ANYP;
  1985. #else
  1986.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1987.     np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1988. #endif
  1989.     np->m_tchars.t_intrc = -1;
  1990.     np->m_tchars.t_quitc = -1;
  1991.     if (!flowctl)
  1992.       { np->m_tchars.t_startc = -1;
  1993.         np->m_tchars.t_stopc = -1;
  1994.       }
  1995.     np->m_ltchars.t_suspc = -1;
  1996.     np->m_ltchars.t_dsuspc = -1;
  1997.     np->m_ltchars.t_flushc = -1;
  1998.     np->m_ltchars.t_lnextc = -1;
  1999.  
  2000. } /* SetMode() */
  2001.  
  2002. #endif /* USE_TERMIO */
  2003. #endif
  2004.  
  2005. static char *
  2006. GetTtyName ()
  2007. {
  2008.     void    Msg();
  2009.     int n;
  2010.     char *p;
  2011.  
  2012.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++);
  2013.  
  2014.     if (!p || *p == '\0')
  2015.         Msg (0, "layers must run on a tty.");
  2016.  
  2017.     return ( p );
  2018.  
  2019. } /* GetTtyName() */
  2020.  
  2021.  
  2022. static void
  2023. Kill (pid, sig)        /* [UNUSED] */
  2024. {
  2025.     if (pid != 0)
  2026.         (void) kill (pid, sig);
  2027. }
  2028.  
  2029.             /* GetSockName() - set SockName; if LTY env return 1 else 0 */
  2030. static int
  2031. GetSockName ()
  2032. {
  2033.     register int client;
  2034.     static char buf[2*MAXSTR];
  2035.  
  2036.     if (!mflag && (SockName = getenv ("LTY")) != 0 && *SockName != '\0')
  2037.       { client = 1;
  2038.         setuid (getuid ());
  2039.         setgid (getgid ());
  2040.       }
  2041.     else
  2042.       { sprintf (buf, "%s.%s", HostName, Filename (RealTtyName));
  2043.         SockName = buf;
  2044.         client = 0;
  2045.       }
  2046.     return client;
  2047.  
  2048. } /* GetSockName() */
  2049.  
  2050. static int
  2051. MakeServerSocket ()
  2052. {
  2053.     void Msg();
  2054.     register int s;
  2055.     struct sockaddr_un a;
  2056.     char *p;
  2057.  
  2058.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  2059.         Msg (errno, "socket");
  2060.     a.sun_family = AF_UNIX;
  2061.     strcpy (SockNamePtr, SockName);
  2062.     strcpy (a.sun_path, SockPath);
  2063.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1)
  2064.       { p = Filename (SockPath);
  2065.         Msg (0, "You already have a layers running on %s.", p);
  2066.         /*NOTREACHED*/
  2067.       }
  2068.     DO DEBUG("MakeServerSocket: unlink(SockPath)/bind()/chown/listen\n");
  2069.     (void) unlink (SockPath);
  2070.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  2071.         Msg (errno, "bind");
  2072.     (void) chown (SockPath, getuid (), getgid ());
  2073.     if (listen (s, 5) == -1)
  2074.         Msg (errno, "listen");
  2075.     return s;
  2076.  
  2077. } /* MakeServerSocket() */
  2078.  
  2079. static int
  2080. MakeClientSocket (err)
  2081. int err;
  2082. {
  2083.     void Msg();
  2084.     register int s;
  2085.     struct sockaddr_un a;
  2086.  
  2087.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  2088.         Msg (errno, "socket");
  2089.     a.sun_family = AF_UNIX;
  2090.     strcpy (SockNamePtr, SockName);
  2091.     strcpy (a.sun_path, SockPath);
  2092.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  2093.       { if (err)
  2094.           { Msg (errno, "connect: %s", SockPath); }
  2095.         else
  2096.           { close (s);
  2097.             return -1;
  2098.           }
  2099.       }
  2100.     return s;
  2101.  
  2102. } /* MakeClientSocket() */
  2103.  
  2104. static void
  2105. SendCreateMsg (s, ac, av, lflag, shape)
  2106. int s, ac, lflag;
  2107. char **av;
  2108. struct Shape *shape;
  2109. {
  2110.     void Msg();
  2111.     struct msg m;
  2112.     register char *p;
  2113.     register len, n;
  2114.     char    *pwd;                    /* PWD environment string */
  2115.  
  2116.     DO DEBUG("SendCreateMsg(%d, ac %d, lflag %d\n", s, ac, lflag);
  2117.     m.type = MSG_CREATE;
  2118.     p = m.m.create.line;
  2119.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n)
  2120.       { len = strlen (*av) + 1;
  2121.         if (p + len >= m.m.create.line+MAXLINE)
  2122.             break;
  2123.         strcpy (p, *av);
  2124.         p += len;
  2125.       }
  2126.     DO DEBUG("  nargs %d, create line = '%s'\n", n, m.m.create.line);
  2127.     m.m.create.nargs = n;
  2128.     m.m.create.lflag = lflag;
  2129.     m.m.create.shape = *shape;            /* pass window shape */
  2130.  
  2131.     /* Since Suns can hang up on getwd() [damn their stupid networking]
  2132.     ** we try to get the current working directory first from the PWD
  2133.     ** environment variable.
  2134.     */
  2135.     if ((pwd=getenv("PWD")) && strlen(pwd) < 1024)
  2136.         (void) strcpy(m.m.create.dir, pwd);
  2137.     else
  2138. #ifdef SVR4
  2139.     if (getcwd (m.m.create.dir, sizeof(m.m.create.dir)) == NULL) {
  2140.         DO DEBUG("getcwd() failed!!\n");
  2141.         Msg (0, "%s", strerror(errno));
  2142.     }
  2143. #else
  2144.     if (getwd (m.m.create.dir) == 0)
  2145.       {    DO DEBUG("getwd() failed!!\n");
  2146.         Msg (0, "%s", m.m.create.dir);
  2147.       }
  2148. #endif
  2149.     DO DEBUG("  create.dir = '%s'\n", m.m.create.dir);
  2150.  
  2151.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  2152.       {    DO DEBUG("  write failed!!\n");
  2153.         Msg (errno, "write");
  2154.       }
  2155.     DO DEBUG("SendCreateMsg() done\n");
  2156.  
  2157. } /* SendCreateMsg() */
  2158.  
  2159. /*VARARGS1*/
  2160. static void
  2161. SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6)
  2162. char *fmt;
  2163. {
  2164.     register s;
  2165.     struct msg m;
  2166.  
  2167.     s = MakeClientSocket (1);
  2168.     m.type = MSG_ERROR;
  2169.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  2170.     (void) write (s, (char *)&m, sizeof (m));
  2171.     close (s);
  2172.     sleep (2);
  2173. }
  2174.  
  2175. static void
  2176. ReceiveMsg (s)
  2177. int s;
  2178. {
  2179.     void Msg();
  2180.     static void ExecCreate();
  2181.  
  2182.     register ns;
  2183.     struct sockaddr_un a;
  2184.     int left, len = sizeof (a);
  2185.     struct msg m;
  2186.     char *p;
  2187.  
  2188.     DO DEBUG ("ReceiveMsg()\n");
  2189.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1)
  2190.       { Msg (errno, "accept");
  2191.         return;
  2192.       }
  2193.     p = (char *)&m;
  2194.     left = sizeof (m);
  2195.     while (left > 0 && (len = read (ns, p, left)) > 0)
  2196.       { p += len;
  2197.         left -= len;
  2198.       }
  2199.     close (ns);
  2200.     if (len == -1)
  2201.         Msg (errno, "read");
  2202.     if (left > 0)
  2203.         return;
  2204.     switch (m.type)
  2205.     { case MSG_CREATE:
  2206.         DO DEBUG("MSG_CREATE:\n");
  2207.         ExecCreate (&m);
  2208.         break;
  2209.  
  2210.       case MSG_ERROR:
  2211.         DO DEBUG("MSG_ERROR:\n");
  2212.         Msg (0, "%s", m.m.message);
  2213.         break;
  2214.  
  2215.       default:
  2216.         Msg (0, "Invalid message (type %d).", m.type);
  2217.  
  2218.     } /* end switch */
  2219.  
  2220. } /* ReceiveMsg() */
  2221.  
  2222. static void
  2223. ExecCreate (mp)
  2224. struct msg *mp;
  2225. {
  2226.     char *args[MAXARGS];
  2227.     register n;
  2228.     register char **pp = args, *p = mp->m.create.line;
  2229.  
  2230.     for (n = mp->m.create.nargs; n > 0; --n)
  2231.       { *pp++ = p;
  2232.         p += strlen (p) + 1;
  2233.       }
  2234.     *pp = 0;
  2235.     n = MakeWindow (0, mp->m.create.line, args, mp->m.create.dir,
  2236.                         mp->m.create.lflag, &mp->m.create.shape);
  2237.  
  2238. } /* ExecCreate() */
  2239.  
  2240.  
  2241. /*
  2242.  * manifest constants for processing .layersrc file:
  2243.  */
  2244.  
  2245. #define    RC_NONE        0
  2246. #define    RC_UNKNOWN    1
  2247. #define    RC_WINDOW    2
  2248.  
  2249. /*
  2250.  *    ProcessGeo():
  2251.  *
  2252.  *        expects passed string to be of the form
  2253.  *
  2254.  *            ###x###                indicating width and height
  2255.  *        or
  2256.  *            ###x###+###+###        indicating width, height, absolute (x,y) position
  2257.  *
  2258.  *        parses string and sets passed shape accordingly
  2259.  *
  2260.  *        returns nonzero if string could not be parsed
  2261.  */
  2262. static
  2263. int    ProcessGeo(shape, p)
  2264. struct Shape *shape;
  2265. char *p;
  2266. {
  2267.     char    buf[256];
  2268.     int        i;
  2269.  
  2270.     int        w, h, x, y;    
  2271.  
  2272.     /* get width: */
  2273.     i = 0;
  2274.     while (isdigit(*p))
  2275.         buf[i++] = *p++;
  2276.  
  2277.     if (*p != 'x')
  2278.         return -1;            /* parse error */
  2279.     buf[i] = '\0';
  2280.  
  2281.     sscanf(buf, "%d", &w);    /* parse width */
  2282.  
  2283.  
  2284.     /* get height: */
  2285.     i = 0; p++;
  2286.     while (isdigit(*p))
  2287.         buf[i++] = *p++;
  2288.  
  2289.     if ((*p) && (*p != '+') && (*p != '-'))
  2290.         return -1;            /* parse error */
  2291.     buf[i] = '\0';
  2292.  
  2293.     sscanf(buf, "%d", &h);    /* parse height */
  2294.  
  2295.     DO DEBUG("ProcessGeo(): %d %d\n", w, h);
  2296.  
  2297.     shape->wchars = w;
  2298.     shape->wlines = h;
  2299.     if (!(*p))
  2300.         return 0;            /* width x height parsed without errors */
  2301.  
  2302.     buf[i=0] = *p++;
  2303.     i++;
  2304.     while (isdigit(*p))
  2305.         buf[i++] = *p++;
  2306.  
  2307.     if ((*p != '+') && (*p != '-'))
  2308.         return -1;        /* parse error */
  2309.     buf[i] = '\0';
  2310.  
  2311.     sscanf(buf, "%d", &x);    /* parse x-position */
  2312.  
  2313.     buf[i=0] = *p++;
  2314.     i++;
  2315.     while (isdigit(*p))
  2316.         buf[i++] = *p++;
  2317.  
  2318.     /* should be end of argument: */
  2319.     if (*p)
  2320.         return -1;            /* parse error */
  2321.     buf[i] = '\0';
  2322.  
  2323.     sscanf(buf, "%d", &y);    /* parse y-position */
  2324.  
  2325.     shape->worigh = x;
  2326.     shape->worigv = y;
  2327.  
  2328.     DO DEBUG("ProcessGeo(): %d %d %d %d\n", w, h, x, y);
  2329.  
  2330.     return 0;                /* width x height x horiz x vert */
  2331. }
  2332.  
  2333. static
  2334. int        InterpretLayerArgs(argc, ap)
  2335. int        argc;
  2336. char   *ap[];
  2337. {
  2338.     char           *progargs[MAXARGS];
  2339.     char           *prog;
  2340.     struct Shape    shape;            /* shape for new window */
  2341.     char           *title = NULL;
  2342.     int                login = 0;        /* login layer */
  2343.     int                retval = 0,
  2344.                     i=0;
  2345.  
  2346.     ClearShape(&shape);                /* initialize shape */
  2347.     progargs[0] = prog = ShellProg;
  2348.     progargs[1] = NULL;
  2349.  
  2350.     while (++i < argc) {
  2351.         if ( (!strcmp("-login", ap[i])) || (!strcmp("-l", ap[i])) )
  2352.             login = 1;
  2353.  
  2354.         else if ( (!strcmp("-geometry", ap[i])) || (!strcmp("-g", ap[i])) ) {
  2355.             if (i+1 < argc) {
  2356.                 i++;
  2357.                 if (ProcessGeo(&shape, ap[i]))
  2358.                     DO DEBUG("InterpretLayerArgs(): error while parsing -geometry argument\n");
  2359.     
  2360.             } else
  2361.                 DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]);
  2362.  
  2363.         } else if ( (!strcmp("-exec", ap[i])) || (!strcmp("-e", ap[i])) ) {
  2364.             if (i+1 < argc) {
  2365.                 int    j=0;
  2366.  
  2367.                 i++;
  2368.                 do {
  2369.                     progargs[j++] = ap[i];
  2370.                 } while (++i < argc);
  2371.                 prog = progargs[0];
  2372.                 progargs[j] = NULL;
  2373.  
  2374.                 } else
  2375.                 DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]);
  2376.  
  2377.         } else if ( (!strcmp("-title", ap[i])) || (!strcmp("-t", ap[i])) ) {
  2378.             if (i+1 < argc)
  2379.                     title = ap[++i];
  2380.             else
  2381.                 DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]);
  2382.         }
  2383.     }
  2384.  
  2385.     shape.wattr |= Wa_shell;            /* indicate a shell window */
  2386.  
  2387.     if ((i=MakeWindow(0, prog, progargs, home, login, &shape)) < 0) {
  2388.         DO DEBUG("InterpretLayerArgs(): MakeWindow() unsuccessful (%d)\n", i);
  2389.     } else {
  2390.         if (title) SendTitle(i, title, strlen(title)); 
  2391.         retval = 1;
  2392.     }
  2393.  
  2394.     return retval;
  2395. }
  2396.  
  2397. static
  2398. int ReadRc (fn)
  2399. char *fn;
  2400. {
  2401.     static int Parse();
  2402.  
  2403.     FILE *f;
  2404.     register char *p, **ap;
  2405.     register argc;
  2406.     char    buf[256];
  2407.     char    *args[MAXARGS];
  2408.  
  2409.     int    rcmode;                /* type of entry */
  2410.  
  2411.     int    l = 0,                /* line within file */
  2412.         i;
  2413.  
  2414.     int    numwin = 0;            /* number of successfully */
  2415.  
  2416.     ap = args;
  2417.  
  2418.     /* insure file can be accessed: */
  2419.     if (access (fn, R_OK) == -1) {
  2420.         DO DEBUG("ReadRc(): cannot access %s\n", fn);
  2421.         return 0;
  2422.     }
  2423.  
  2424.     /* open file for reading: */ 
  2425.     if ((f = fopen (fn, "r")) == NULL) {
  2426.         DO DEBUG("ReadRc(): cannot open %s\n", fn);
  2427.         return 0;
  2428.     }
  2429.  
  2430.     /* for each line in file: */
  2431.     while (fgets (buf, 256, f) != NULL) {
  2432.         l++;
  2433.  
  2434.         /* terminate string with '\0': */
  2435.         if (p = index (buf, '\n'))
  2436.             *p = '\0';
  2437.  
  2438.         argc = Parse (fn, buf, ap);
  2439.         if (Dflag) for (i=0; i<argc; i++) 
  2440.             DO DEBUG("ReadRc(): line %d, token %d: \"%s\"\n", 
  2441.                     l, i, ap[i]);
  2442.  
  2443.         rcmode = RC_NONE;
  2444.         if ((argc == 0) || (!strcmp(ap[0], "#")))
  2445.             /* ignore */;
  2446.         else if (!strcmp(ap[0], "layer"))
  2447.             rcmode = RC_WINDOW;
  2448.         else
  2449.             rcmode = RC_UNKNOWN;
  2450.  
  2451.         i = 0;
  2452.         switch (rcmode) {
  2453.             case RC_UNKNOWN :
  2454.                 DO DEBUG("ReadRc(): unknown keyword (%s)\n", ap[0]);
  2455.                 break;
  2456.  
  2457.             case RC_WINDOW : {
  2458.                 numwin += InterpretLayerArgs(argc, ap);
  2459.             }
  2460.             break;
  2461.  
  2462.             default :
  2463.                 /* ignore blank lines and comments */
  2464.                 break;
  2465.         }
  2466.         
  2467.  
  2468.     }
  2469.  
  2470.     (void) fclose (f);
  2471.  
  2472.     return numwin;
  2473.  
  2474. } /* ReadRc() */
  2475.  
  2476. static int
  2477. Parse (fn, buf, args)
  2478. char *fn, *buf, **args;
  2479. {
  2480.     void Msg();
  2481.  
  2482.     register char *p, **ap;
  2483.     register delim, argc;
  2484.  
  2485.     p = buf;
  2486.     ap = args;
  2487.     argc = 0;
  2488.     for (;;)
  2489.       { while (*p && (*p == ' ' || *p == '\t'))
  2490.             ++p;
  2491.         if (*p == '\0' || *p == '#')
  2492.             return argc;
  2493.         if (argc > MAXARGS-1)
  2494.             Msg (0, "%s: too many tokens.", fn);
  2495.         delim = 0;
  2496.         if (*p == '"' || *p == '\'')
  2497.           { delim = *p; *p = '\0'; ++p; }
  2498.         ++argc;
  2499.         *ap = p; ++ap;
  2500.         while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  2501.             ++p;
  2502.         if (*p == '\0')
  2503.           { if (delim)
  2504.                 Msg (0, "%s: Missing quote.", fn);
  2505.             else
  2506.                 return argc;
  2507.           }
  2508.         *p++ = '\0';
  2509.       }
  2510.  
  2511. } /* Parse() */
  2512.  
  2513. static char **
  2514. SaveArgs (argc, argv)            /* [UNUSED] */
  2515. register argc;
  2516. register char **argv;
  2517. {
  2518.     void Msg();
  2519.     register char **ap, **pp;
  2520.  
  2521.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  2522.         Msg (0, "Out of memory.");
  2523.     while (argc--)
  2524.       { if ((*pp = malloc (strlen (*argv)+1)) == 0)
  2525.             Msg (0, "Out of memory.");
  2526.         strcpy (*pp, *argv);
  2527.         ++pp; ++argv;
  2528.       }
  2529.     *pp = 0;
  2530.     return ap;
  2531.  
  2532. } /* SaveArgs() */
  2533.  
  2534. static void
  2535. MakeNewEnv ()
  2536. {
  2537.     static int IsSymbol();
  2538.  
  2539.     register char **op, **np = NewEnv;
  2540.     static char buf[MAXSTR];
  2541.  
  2542.     if ((int) strlen (SockName) > MAXSTR-5)
  2543.         SockName = "?";
  2544.     sprintf (buf, "LTY=%s", SockName);
  2545.     *np++ = buf;
  2546.     *np++ = Term;
  2547.     np += 2;
  2548.     for (op = environ; *op; ++op)
  2549.       { if (np == NewEnv + MAXARGS - 1)
  2550.             break;
  2551.         if (   !IsSymbol (*op, "TERM")
  2552.             && !IsSymbol (*op, "TERMCAP")
  2553.             && !IsSymbol (*op, "LTY")
  2554.            )
  2555.             *np++ = *op;
  2556.       }
  2557.     *np = 0;
  2558.  
  2559. } /* MakeNewEnv() */
  2560.  
  2561. static int
  2562. IsSymbol (e, s)
  2563. register char *e, *s;
  2564. {
  2565.     register char *p;
  2566.     register n;
  2567.  
  2568.     for (p = e; *p && *p != '='; ++p);
  2569.     if (*p)
  2570.       { *p = '\0';
  2571.         n = strcmp (e, s);
  2572.         *p = '=';
  2573.         return n == 0;
  2574.       }
  2575.  
  2576.     return 0;
  2577.  
  2578. } /* IsSymbol() */
  2579.  
  2580. /*VARARGS2*/
  2581. void
  2582. Msg (err, fmt, p1, p2, p3, p4, p5, p6)
  2583. int err;
  2584. char *fmt;
  2585. {
  2586.     char buf[1024];
  2587.     register char *p = buf;
  2588.  
  2589.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  2590.     if (err) {
  2591.         p += strlen (p);
  2592.         if (err > 0 && err < sys_nerr)
  2593.             sprintf (p, ": %s", sys_errlist[err]);
  2594.         else
  2595.             sprintf (p, ": Error %d", err);
  2596.     }
  2597.  
  2598.     if (!Abortonmsg) {
  2599.         /* MakeStatus (buf, curr);*/
  2600.         printf("%s\r\n", buf);
  2601.         fflush(stdout);
  2602.     } else {
  2603.         printf ("%s\r\n", buf);
  2604.         fflush(stdout);
  2605.  
  2606.         if (Resetenvonmsg) {
  2607.             SetTTY (0, &OldMode);
  2608.             if (RealTtyMode)
  2609.                 (void) chmod(RealTtyName, RealTtyMode);    /* restore mode */
  2610.             RestoreRealUtmp();
  2611.             FinitTerm ();
  2612.         }
  2613.         exit(exitcode);
  2614.     }
  2615.  
  2616. } /* Msg() */
  2617.  
  2618. static char *
  2619. Filename (s)
  2620. char *s;
  2621. {
  2622.     register char *p;
  2623.  
  2624.     p = s + strlen (s) - 1;
  2625.     while (p >= s && *p != '/')
  2626.         --p;
  2627.     return ++p;
  2628.  
  2629. } /* Filename() */
  2630.  
  2631. static int
  2632. IsNum (s, base)            /* [UNUSED] */
  2633. register char *s;
  2634. register base;
  2635. {
  2636.     for (base += '0'; *s; ++s)
  2637.         if (*s < '0' || *s > base)
  2638.             return 0;
  2639.     return 1;
  2640.  
  2641. } /* IsNum() */
  2642.  
  2643. #ifndef GETTTYENT
  2644.  
  2645. static
  2646. setttyent ()
  2647. {
  2648.     struct stat s;
  2649.     register f;
  2650.     register char *p, *ep;
  2651.  
  2652.     if (ttnext)
  2653.       { ttnext = tt;
  2654.         return;
  2655.       }
  2656.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  2657.         Msg (errno, ttys);
  2658.     if ((tt = malloc (s.st_size + 1)) == 0)
  2659.         Msg (0, "Out of memory.");
  2660.     if (read (f, tt, s.st_size) != s.st_size)
  2661.         Msg (errno, ttys);
  2662.     close (f);
  2663.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  2664.         if (*p == '\n')
  2665.             *p = '\0';
  2666.     *p = '\0';
  2667.     ttnext = tt;
  2668.  
  2669. } /* setttyent() */
  2670.  
  2671. static struct ttyent *
  2672. getttyent ()
  2673. {
  2674.     static struct ttyent t;
  2675.  
  2676.     if (*ttnext == '\0')
  2677.         return NULL;
  2678.     t.ty_name = ttnext + 2;
  2679.     ttnext += strlen (ttnext) + 1;
  2680.     return &t;
  2681.  
  2682. } /* getttyend() */
  2683.  
  2684. #endif
  2685.  
  2686.  
  2687.                     /* FinitTerm() - reset vt100 terminal */
  2688. static void
  2689. FinitTerm ()
  2690. {
  2691.     /* print out termcap 'is' string to reset terminal */
  2692. #if 0
  2693.     /* This string sets scroll region 1-24 and puts cursor at bottom line */
  2694.     puts("\033[1;24r\033[24;1H", stdout);
  2695. #endif
  2696.     fflush(stdout);
  2697. }
  2698.  
  2699. static void
  2700. AddCap (s)
  2701. char *s;
  2702. {
  2703.     register n;
  2704.  
  2705.     if (tcLineLen + (n = strlen (s)) > 55)
  2706.       { strcat (Termcap, "\\\n\t:");
  2707.         tcLineLen = 0;
  2708.       }
  2709.     strcat (Termcap, s);
  2710.     tcLineLen += n;
  2711. }
  2712.  
  2713. static char *
  2714. MakeTermcap(lines, chars)
  2715. int        lines;                            /* default window lines */
  2716. int        chars;                            /* default window chars */
  2717. {
  2718.     char buf[1024];
  2719.  
  2720.     strcpy(Termcap, TermcapConst1);        /* start TERMCAP build */
  2721.     strcat(Termcap, UserTerm);            /* fill in User's terminal type */
  2722.     strcat(Termcap, TermcapConst3);        /* finish our own definition */
  2723.  
  2724.     /* add more capabilities depending upon client version */
  2725.     if (Protocollevel > 1)
  2726.         strcat(Termcap, TermcapConst101);
  2727.  
  2728.     if (lines <= 0 || lines > 200)
  2729.         lines = rows;                    /* force default if none or invalid */
  2730.     if (chars <= 0 || chars > 300)
  2731.         chars = cols;                    /* force default if none or invalid */
  2732.  
  2733.     sprintf(buf, "li#%d:co#%d:", lines, chars);
  2734.     AddCap(buf);
  2735.  
  2736.     return ( Termcap );
  2737.  
  2738. } /* MakeTermcap() */
  2739.  
  2740.  
  2741.                 /* DEBUG() - dump output routine */
  2742.  
  2743. void
  2744. DEBUG(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
  2745. char        *format;
  2746. int            arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8;
  2747. {
  2748.     fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
  2749. }
  2750.  
  2751.  
  2752. #ifdef SVR4
  2753. static struct utmpx   RealUtmp;       /* Real tty logon utmpx entry */
  2754. #else
  2755. static struct utmp    RealUtmp;       /* Real tty logon utmp entry */
  2756. #endif
  2757.  
  2758. /*
  2759.  * Utmp functions for SYSV and Sun BSD:
  2760.  *     (Note: Appropriate utmpx functions for SVR4 follow)
  2761.  *
  2762.  * InitUtmp()           - Zero out main utmp entry for controlling tty
  2763.  *                         and save old value.
  2764.  * SetUtmp()           - Add a tty to utmp, "login" a new terminal
  2765.  * RemoveTtyFromUtmp() - "logout" a terminal
  2766.  * RestoreRealUtmp()   - Restore original utmp entry for controlling tty
  2767.  */
  2768.  
  2769. #ifdef SYSVUTMP
  2770.  
  2771. static char UtmpName[] = "/etc/utmp";
  2772. #ifdef AUX
  2773. static char WtmpName[] = "/etc/wtmp";
  2774. #endif
  2775. static int  RealSlot = 0;                       /* Real tty logon slot */
  2776.  
  2777. static void ut_tty_cpy(struct utmp *up, char * tty)
  2778. {
  2779.     strncpy(up->ut_line, Filename(tty), sizeof up->ut_line);
  2780.     up->ut_line[(sizeof up->ut_line) - 1] = '\0';
  2781. }
  2782.  
  2783. static void
  2784. ReadUtmp(int slot, struct utmp *entry)
  2785. {
  2786.     int     i;
  2787.     struct utmp *ret;
  2788.     
  2789.     setutent();
  2790.     for (i=0; i<slot; i++)                /* read and discard ... */
  2791.         (void) getutent();
  2792.  
  2793.     ret = getutent();                        /* ... until we get to our entry */
  2794.     *entry = *ret;
  2795.  
  2796.     DO DEBUG("ReadUtmp slot %d errno %d, line %.8s, name %.8s\n",
  2797.         slot, errno, entry->ut_line, entry->ut_name);
  2798.  
  2799. } /* ReadUtmp() */
  2800.  
  2801. static void
  2802. RemoveUtmp(int slot)
  2803. {
  2804.     struct utmp    u;
  2805. #ifdef AUX
  2806.     int wtmpfd;
  2807. #endif
  2808.  
  2809.     if (slot) {
  2810.         setutent();
  2811.         ReadUtmp(slot, &u);
  2812.         u.ut_type = DEAD_PROCESS;
  2813.         pututline(&u);
  2814. #ifdef AUX
  2815.         if ((wtmpfd = open(WtmpName,1)) >= 0) {
  2816.             lseek (wtmpfd, 0L, 2);
  2817.             write (wtmpfd, (char *)&u, sizeof(u));
  2818.             close (wtmpfd);
  2819.         }
  2820. #endif
  2821.     }
  2822. }
  2823.  
  2824. static int
  2825. FindUtmp(char *name)
  2826. {
  2827.     register char *p;
  2828.     register struct utmp *u;
  2829.     register slot = 0;
  2830.  
  2831.     if (p = rindex (name, '/'))
  2832.         ++p;
  2833.     else
  2834.         p = name;
  2835.  
  2836.     setutent();
  2837.     while ((u = getutent()) != NULL && strcmp(p, u->ut_line) != 0) {
  2838.         ++slot;
  2839.     }
  2840.  
  2841.     if (u == NULL)
  2842.         return 0;
  2843.  
  2844.     return slot;
  2845. }
  2846.  
  2847. static void
  2848. InitUtmp()
  2849. {
  2850.     struct utmp *ret;
  2851.  
  2852.     RealSlot = FindUtmp(RealTtyName);        /* find current logon slot */
  2853.     DO DEBUG("InitUtmp(): RealSlot = %d\n", RealSlot);
  2854.     if (RealSlot) {
  2855.         ReadUtmp(RealSlot, &RealUtmp);
  2856.         RemoveUtmp(RealSlot);
  2857.     } else
  2858.         RealUtmp.ut_type = DEAD_PROCESS;
  2859. }
  2860.  
  2861. static void
  2862. RestoreRealUtmp()
  2863. {
  2864.     if (RealUtmp.ut_type != EMPTY) {
  2865.         struct utmp *ret;
  2866. #ifdef AUX
  2867.         int wtmpfd;
  2868. #endif
  2869.  
  2870.         setutent();
  2871.         RealUtmp.ut_type = USER_PROCESS; 
  2872.         pututline(&RealUtmp);
  2873. #ifdef AUX
  2874.         if ((wtmpfd = open(WtmpName,1)) >= 0) {
  2875.             lseek (wtmpfd, 0L, 2);
  2876.             write (wtmpfd, (char *)&RealUtmp, sizeof(RealUtmp));
  2877.             close (wtmpfd);
  2878.         }
  2879. #endif
  2880.     } else
  2881.         DO DEBUG("RestoreRealUtmp(): RealUtmp.ut_type == EMPTY\n");
  2882. }
  2883.  
  2884. static int
  2885. SetUtmp(char *tty, int isreal, int lpid)
  2886. {
  2887.     register char *p;
  2888.     struct utmp ut, *ret;
  2889. #ifdef AUX
  2890.     int wtmpfd;
  2891. #endif
  2892.  
  2893.     DO DEBUG("SetUtmp(): tty = %s, isreal = %d, lpid = %d\n", tty, isreal, lpid);
  2894.  
  2895.     if (p = rindex(tty, '/'))
  2896.         ++p;
  2897.     else
  2898.         p = tty;
  2899.  
  2900.     setutent();
  2901.     strncpy(ut.ut_line, p, 8);
  2902.     ret = getutline(&ut);
  2903.     if (ret == NULL) {
  2904.         DO DEBUG("SetUtmp(): cannot locate utmp entry for %s\n", p);
  2905.         ret = &ut;
  2906.     }
  2907.  
  2908.     strncpy(ret->ut_line, p, 8);
  2909. #ifdef AUX
  2910.     ret->ut_id[0] = 'p';
  2911.     ret->ut_id[1] = 't';
  2912.     ret->ut_id[2] = ret->ut_line[3];
  2913.     ret->ut_id[3] = ret->ut_line[4];
  2914. #endif
  2915.     strncpy(ret->ut_user, LoginName, 8);
  2916.     if (RealSlot && isreal)
  2917.         ret->ut_time = RealUtmp.ut_time;       /* use original login time */
  2918.     else
  2919.         time(&(ret->ut_time));
  2920.  
  2921.     ret->ut_pid = lpid;
  2922.     ret->ut_type = USER_PROCESS;
  2923.  
  2924.     pututline(ret);
  2925. #ifdef AUX
  2926.     if ((wtmpfd = open(WtmpName,1)) >= 0) {
  2927.         lseek (wtmpfd, 0L, 2);
  2928.         write (wtmpfd, (char *)ret, sizeof(*ret));
  2929.         close (wtmpfd);
  2930.     }
  2931. #endif
  2932.     return FindUtmp(p);
  2933. }
  2934.  
  2935. static void RemoveTtyFromUtmp(struct Layer *l)
  2936. {
  2937.     struct utmp ut, *ret;
  2938. #ifdef AUX
  2939.     int wtmpfd;
  2940. #endif
  2941.  
  2942.     setutent();
  2943.     ut_tty_cpy(&ut, l->tty);
  2944.     ret = getutline(&ut);
  2945.     if (ret) {
  2946.         ret->ut_type = DEAD_PROCESS;
  2947.         pututline(ret);
  2948.     }
  2949. #ifdef AUX
  2950.     if ((wtmpfd = open(WtmpName,1)) >= 0) {
  2951.         lseek (wtmpfd, 0L, 2);
  2952.         write (wtmpfd, (char *)ret, sizeof(*ret));
  2953.         close (wtmpfd);
  2954.     }
  2955. #endif
  2956. }
  2957.  
  2958. #else
  2959.  
  2960. #ifndef SVR4
  2961. static char UtmpName[] = "/etc/utmp";
  2962. static int    RealSlot = 0;                        /* Real tty logon slot */
  2963.  
  2964. static int
  2965. FindUtmp(name)
  2966. char *name;
  2967. {
  2968.     register char *p;
  2969.     register struct ttyent *tp;
  2970.     register slot;
  2971.  
  2972.     DO DEBUG("FindUtmp(%s)\n", name);
  2973.     slot = 1;
  2974.     if (!utmp)
  2975.         return 0;
  2976.     if (p = rindex (name, '/'))
  2977.         ++p;
  2978.     else
  2979.         p = name;
  2980.     setttyent ();
  2981.     while (   (tp = getttyent ()) != NULL
  2982.            && strcmp (p, tp->ty_name) != 0
  2983.           )
  2984.         ++slot;
  2985.     if (tp == NULL)
  2986.         return 0;
  2987.  
  2988.     DO DEBUG(" slot %d\n", slot);
  2989.     return slot;
  2990.  
  2991. } /* FindUtmp() */
  2992.  
  2993. static int
  2994. SetUtmp (name, mainlogin, lpid)
  2995. char    *name;                            /* tty name */
  2996. int        mainlogin;                        /* this is primary login */
  2997. int        lpid;
  2998. {
  2999.     register char *p;
  3000.     register slot;
  3001.     struct utmp u;
  3002.  
  3003.     if ((slot=FindUtmp(name)) == 0)
  3004.         return ( 0 );
  3005.  
  3006.     if (p = rindex (name, '/'))
  3007.         ++p;
  3008.     else
  3009.         p = name;
  3010.  
  3011.     strncpy (u.ut_line, p, 8);
  3012.     strncpy (u.ut_name, LoginName, 8);
  3013.     strncpy(u.ut_host,  Filename (RealTtyName), 16); /* host is real tty */
  3014.     if (RealSlot && mainlogin)
  3015.         u.ut_time = RealUtmp.ut_time;        /* use original login time */
  3016.     else
  3017.         time (&u.ut_time);
  3018.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  3019.     (void) write (utmpf, (char *)&u, sizeof (u));
  3020.  
  3021.     return ( slot );
  3022.  
  3023. } /* SetUtmp() */
  3024.  
  3025. static int
  3026. ReadUtmp(slot, entry)
  3027. int        slot;                                /* slot to read */
  3028. struct utmp    *entry;                            /* entry to read into */
  3029. {
  3030.     int        cnt;                            /* return count */
  3031.  
  3032.     if (!utmp)
  3033.         exit(EXITABNORMAL);                    /* no utmp access */
  3034.  
  3035.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  3036.     cnt =  read(utmpf, (char *)entry, sizeof(struct utmp));
  3037.     DO DEBUG("ReadUtmp cnt %d, errno %d, line %.8s, name %.8s, host %.16s\n",
  3038.         cnt, errno, entry->ut_line, entry->ut_name, entry->ut_host);
  3039.  
  3040.     return ( cnt );
  3041.  
  3042. } /* ReadUtmp() */
  3043.  
  3044. static void
  3045. WriteUtmp(slot, entry)
  3046. int        slot;                                /* slot to write */
  3047. struct utmp    *entry;                            /* entry to write from */
  3048. {
  3049.     int        cnt;                            /* write return code */
  3050.  
  3051.     if (!utmp)
  3052.         return;                                /* no utmp access */
  3053.  
  3054.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  3055.     cnt = write(utmpf, (char *)entry, sizeof(struct utmp));
  3056.     DO DEBUG("WriteUtmp() slot %d cnt %d line %.8s name %.8s host %.16s\n",
  3057.                 slot, cnt, entry->ut_line, entry->ut_name, entry->ut_host);
  3058.  
  3059. } /* WriteUtmp() */
  3060.  
  3061. static void
  3062. RemoveUtmp (slot)
  3063. int    slot;
  3064. {
  3065.     struct utmp u;
  3066.  
  3067.     if (slot)
  3068.       { bzero ((char *)&u, sizeof (u));
  3069.         (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  3070.         (void) write (utmpf, (char *)&u, sizeof (u));
  3071.       }
  3072.  
  3073. } /* RemoveUtmp() */
  3074.  
  3075. static void
  3076. RemoveTtyFromUtmp(layer)
  3077. struct Layer *layer;
  3078. {
  3079.     RemoveUtmp(layer->slot);
  3080. }
  3081.  
  3082. static void
  3083. InitUtmp ()
  3084. {
  3085.     if ((utmpf = open (UtmpName, O_RDWR)) == -1)
  3086.       { if (errno != EACCES)
  3087.             Msg (errno, UtmpName);
  3088.         return;
  3089.       }
  3090.     utmp = 1;
  3091.  
  3092.     RealSlot = FindUtmp(RealTtyName);    /* find current logon slot */
  3093.     if (RealSlot)
  3094.       {    if (ReadUtmp(RealSlot, &RealUtmp) > 0)    /* read real login utmp */
  3095.             RemoveUtmp(RealSlot);        /* remove original logon slot */
  3096.         else
  3097.             RealSlot = 0;                /* something's wrong */
  3098.       }
  3099. }
  3100.  
  3101. static void
  3102. RestoreRealUtmp()
  3103. {
  3104.     if (RealSlot)
  3105.         WriteUtmp(RealSlot, &RealUtmp);    /* restore original login */
  3106. }
  3107. #endif /* !SVR4 */
  3108. #endif
  3109.  
  3110. #ifdef SVR4
  3111. static void
  3112. ut_tty_cpy(struct utmpx *up, char * tty)
  3113. {
  3114.     strncpy(up->ut_line, strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty,
  3115.         sizeof up->ut_line);
  3116.     up->ut_line[(sizeof up->ut_line) - 1] = '\0';
  3117. }
  3118.  
  3119. static void
  3120. InitUtmp()
  3121. {
  3122.     struct utmpx *ret;
  3123.  
  3124.     setutxent();
  3125.     ut_tty_cpy(&RealUtmp, RealTtyName);
  3126.     if ((ret = getutxline(&RealUtmp)) != NULL) {
  3127.         RealUtmp = *ret;
  3128.         RealUtmp.ut_type = LOGIN_PROCESS;
  3129.         pututxline(&RealUtmp);
  3130.     } else
  3131.         RealUtmp.ut_type = EMPTY;
  3132.     endutxent();
  3133. }
  3134.  
  3135. static void
  3136. RestoreRealUtmp()
  3137. {
  3138.     if (RealUtmp.ut_type == LOGIN_PROCESS) {
  3139.         struct utmpx *ret;
  3140.  
  3141.         setutxent();
  3142.         ret = getutxline(&RealUtmp);
  3143.         if (ret != NULL) {
  3144.             RealUtmp.ut_type = USER_PROCESS;
  3145.             pututxline(&RealUtmp);
  3146.         }
  3147.         endutxent();
  3148.     }
  3149. }
  3150.  
  3151. static int
  3152. SetUtmp(char *tty, int chan, int lpid)
  3153. {
  3154.     struct utmpx ut, *ret;
  3155.     char    buf[8];
  3156.  
  3157.     setutxent();
  3158.     ut_tty_cpy(&ut, tty);
  3159.     ret = getutxline(&ut);
  3160.     if (ret == NULL)
  3161.         ret = &ut;
  3162.     *ret = RealUtmp;
  3163.     ut_tty_cpy(ret, tty);
  3164.     (void) sprintf(buf, "ml%02d", chan);
  3165.     (void) strncpy(ret->ut_id, buf, sizeof(ret->ut_id));
  3166.     ret->ut_pid = lpid;
  3167.     ret->ut_type = USER_PROCESS;
  3168.     if (chan != 1)
  3169.         gettimeofday(&ret->ut_tv);
  3170.     (void) strncpy(ret->ut_host, RealTtyName, sizeof(ret->ut_host));
  3171.     ret->ut_syslen = strlen(RealTtyName) + 1;
  3172.     pututxline(ret);
  3173.     endutxent();
  3174. }
  3175.  
  3176. static void
  3177. RemoveTtyFromUtmp(struct Layer *l)
  3178. {
  3179.     struct utmpx ut, *ret;
  3180.     char    buf[8];
  3181.  
  3182.     setutxent();
  3183.     memset(&ut, '\0', sizeof(ut));
  3184.     ut_tty_cpy(&ut, l->tty);
  3185.     (void) sprintf(buf, "ml%02d", l->chan);
  3186.     (void) strncpy(ut.ut_id, buf, sizeof(ut.ut_id));
  3187.     ret = getutxline(&ut);
  3188.     if (ret != NULL) {
  3189.         ret->ut_type = DEAD_PROCESS;
  3190.         pututxline(ret);
  3191.     }
  3192.     endutxent();
  3193. }
  3194. #endif /* SVR4 */
  3195.  
  3196.